1use crate::cst::Token;
4use crate::{Parse, ParseStream, Spanned, ToTokens, TokenParseError, TokenStream};
5
6type Semicolon = Token![;];
7
8#[derive(Debug, Clone, PartialEq, Eq, Spanned)]
10pub struct Terminated<S> {
11 pub statement: S,
12 pub semicolon: Semicolon,
13}
14
15impl<S> Terminated<S> {
16 pub fn new(statement: S, semicolon: Semicolon) -> Self {
18 Self {
19 statement,
20 semicolon,
21 }
22 }
23}
24
25impl<S: Parse> Parse for Terminated<S> {
26 fn parse(input: &mut ParseStream) -> Result<Self, TokenParseError> {
27 reject_empty_statement(input)?;
28 Ok(Self::new(S::parse(input)?, Parse::parse(input)?))
29 }
30}
31
32impl<S: ToTokens> ToTokens for Terminated<S> {
33 fn to_tokens(&self, output: &mut TokenStream) {
34 self.statement.to_tokens(output);
35 self.semicolon.to_tokens(output);
36 }
37}
38
39#[derive(Debug, Clone, PartialEq, Eq, Spanned)]
44pub struct Body<S> {
45 pub statements: Vec<Terminated<S>>,
46 pub tail: Option<S>,
47}
48
49impl<S> Body<S> {
50 pub fn new(statements: Vec<Terminated<S>>, tail: Option<S>) -> Self {
52 Self { statements, tail }
53 }
54}
55
56impl<S: Parse> Parse for Body<S> {
57 fn parse(input: &mut ParseStream) -> Result<Self, TokenParseError> {
58 let mut statements = Vec::new();
59 while !input.is_eof() {
60 reject_empty_statement(input)?;
61 let statement = S::parse(input)?;
62 if input
63 .peek()
64 .is_some_and(<Semicolon as Token>::matches_token_tree)
65 {
66 statements.push(Terminated::new(statement, Parse::parse(input)?));
67 } else {
68 return Ok(Self::new(statements, Some(statement)));
69 }
70 }
71 Ok(Self::new(statements, None))
72 }
73}
74
75fn reject_empty_statement(input: &ParseStream) -> Result<(), TokenParseError> {
76 let Some(token) = input
77 .peek()
78 .filter(|token| <Semicolon as Token>::matches_token_tree(token))
79 else {
80 return Ok(());
81 };
82 Err(TokenParseError::UnexpectedToken {
83 expected: "a statement before `;`",
84 found: ";".to_owned(),
85 span: token.span(),
86 })
87}
88
89impl<S: ToTokens> ToTokens for Body<S> {
90 fn to_tokens(&self, output: &mut TokenStream) {
91 self.statements.to_tokens(output);
92 self.tail.to_tokens(output);
93 }
94}