Skip to main content

rustidy_parse/
whitespace.rs

1//! Whitespace impls
2
3// Imports
4use {
5	crate::{self as rustidy_parse, Parse, ParseError, Parser, ParserError, ParserTag},
6	rustidy_util::{
7		ArenaIdx,
8		whitespace::{
9			BlockComment,
10			Comment,
11			LineComment,
12			PureWhitespace,
13			Whitespace,
14			WhitespaceInner,
15		},
16	},
17};
18
19impl Parse for Whitespace {
20	type Error = WhitespaceError;
21
22	fn parse_from(parser: &mut Parser) -> Result<Self, Self::Error> {
23		if parser.has_tag(ParserTag::SkipWhitespace) {
24			let (s, ()) = parser.update_with(|_| ());
25			let inner = WhitespaceInner { first: PureWhitespace(s), rest: vec![], };
26			let idx = ArenaIdx::new(inner);
27
28			return Ok(Self(idx));
29		}
30
31		parser
32			.parse::<ArenaIdx<WhitespaceInner>>()
33			.map(Self).map_err(WhitespaceError)
34	}
35}
36
37#[derive(Debug, derive_more::From, ParseError)]
38#[parse_error(transparent)]
39pub struct WhitespaceError(ParserError<ArenaIdx<WhitespaceInner>>);
40
41
42impl Parse for WhitespaceInner {
43	type Error = WhitespaceInnerError;
44
45	fn parse_from(parser: &mut Parser) -> Result<Self, Self::Error> {
46		let first = parser.parse::<PureWhitespace>()?;
47		let mut rest = vec![];
48		while let Ok(comment) = parser.try_parse::<Comment>()? {
49			let pure = parser.parse::<PureWhitespace>()?;
50			rest.push((comment, pure));
51		}
52
53		Ok(Self { first, rest })
54	}
55}
56
57#[derive(Debug, derive_more::From, ParseError)]
58pub enum WhitespaceInnerError {
59	Pure(ParserError<PureWhitespace>),
60	Comment(ParserError<Comment>),
61}
62
63
64impl Parse for Comment {
65	type Error = CommentError;
66
67	fn parse_from(parser: &mut Parser) -> Result<Self, Self::Error> {
68		let block_err = match parser.try_parse().map_err(CommentError::Block)? {
69			Ok(block) => return Ok(Self::Block(block)),
70			Err(err) => err,
71		};
72
73		let line_err = match parser.try_parse().map_err(CommentError::Line)? {
74			Ok(line) => return Ok(Self::Line(line)),
75			Err(err) => err,
76		};
77
78		Err(
79			CommentError::None { block: block_err, line: line_err, }
80		)
81	}
82}
83
84#[derive(Debug, ParseError)]
85pub enum CommentError {
86	#[parse_error(transparent)]
87	Block(ParserError<BlockComment>),
88	#[parse_error(transparent)]
89	Line(ParserError<LineComment>),
90
91	#[parse_error(fmt = "Expected a block or line comment")]
92	#[parse_error(multiple)]
93	None {
94		block: ParserError<BlockComment>,
95		line:  ParserError<LineComment>,
96	},
97}
98
99
100impl Parse for BlockComment {
101	type Error = BlockCommentError;
102
103	fn parse_from(parser: &mut Parser) -> Result<Self, Self::Error> {
104		parser.try_update_with(|s| {
105			let is_doc_comment = (s.starts_with("/**") && !s.starts_with("/***") && !s.starts_with("/**/")) || s.starts_with("/*!");
106
107			match s.strip_prefix("/*") {
108				Some(rest) if !is_doc_comment => {
109					*s = rest;
110					let mut depth = 1;
111					while depth != 0 {
112						let close_idx = s
113							.find("*/")
114							.ok_or(BlockCommentError::MissingCommentEnd)?;
115
116						match s[..close_idx].find("/*") {
117							Some(open_idx) => {
118								*s = &s[open_idx + 2..];
119								depth += 1;
120							},
121							None => {
122								*s = &s[close_idx + 2..];
123								depth -= 1;
124							},
125						}
126					}
127					Ok(())
128				},
129				_ => Err(BlockCommentError::NoComment),
130			}
131		}).map(|(s, ())| Self(s))
132	}
133}
134
135#[derive(Debug, ParseError)]
136pub enum BlockCommentError {
137	#[parse_error(fmt = "Expected `/*` (except `/*!` or `/**`)")]
138	NoComment,
139	#[parse_error(fmt = "Expected `*/` after `/*`")]
140	#[parse_error(fatal)]
141	MissingCommentEnd,
142}
143
144
145impl Parse for LineComment {
146	type Error = LineCommentError;
147
148	fn parse_from(parser: &mut Parser) -> Result<Self, Self::Error> {
149		parser.try_update_with(|s| {
150			let is_doc_comment = (s.starts_with("///") && !s.starts_with("////")) || s.starts_with("//!");
151			match s.starts_with("//") && !is_doc_comment {
152				true => {
153					*s = match s.find('\n') {
154						Some(idx) => &s[idx + 1..],
155						None => &s[s.len()..],
156					};
157					Ok(())
158				},
159				false => Err(LineCommentError::NoComment),
160			}
161		}).map(|(s, ())| Self(s))
162	}
163}
164
165#[derive(Debug, ParseError)]
166pub enum LineCommentError {
167	#[parse_error(fmt = "Expected `//` (except `///` or `//!`)")]
168	NoComment,
169}
170
171
172impl Parse for PureWhitespace {
173	type Error = !;
174
175	fn parse_from(parser: &mut Parser) -> Result<Self, Self::Error> {
176		let (s, ()) = parser.update_with(|s| *s = s.trim_start());
177		Ok(Self(s))
178	}
179}