//! Contains the syntax tree nodes that represent the structure of the source code. use derive_more::derive::From; use getset::Getters; use crate::{ base::{ self, source_file::{SourceElement, Span}, Handler, VoidHandler, }, lexical::{ token::{MacroStringLiteral, Punctuation, StringLiteral, Token}, token_stream::Delimiter, }, syntax::parser::Reading, }; use super::{error::ParseResult, parser::Parser}; pub mod condition; pub mod declaration; pub mod expression; pub mod program; pub mod statement; /// Represents a syntax tree node with a pattern of syntax tree nodes separated by a separator. /// /// This struct is useful for representing syntax tree nodes that are separated by a separator. /// For example, a comma separated list of expressions such as `1, 2, 3` can be represented by a /// [`ConnectedList`] with the separator being a comma token and the elements being the expressions. #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Getters)] pub struct ConnectedList { /// The first element of the list. #[get = "pub"] first: Element, /// The rest of the elements of the list. /// /// Each element of the list is a tuple containing the separator and the element. The separator /// is the token/syntax tree node that separates the current element from the prior one. #[get = "pub"] rest: Vec<(Separator, Element)>, /// The trailing separator of the list. #[get = "pub"] trailing_separator: Option, } /// Represents a syntax tree node with a pattern of having [`ConnectedList`] delimited by a pair of /// punctuation like such `(a, b, c)`. #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct DelimitedList { /// The open punctuation of the list. pub open: Punctuation, /// The list of elements of the list. /// /// If `None` then the list is empty (or immediately closed after the open punctuation). pub list: Option>, /// The close punctuation of the list. pub close: Punctuation, } /// Represents a syntax tree node that can be either a string literal or a macro string literal. /// /// Syntax Synopsis: /// ```ebnf /// AnyStringLiteral: StringLiteral | MacroStringLiteral ; /// ``` #[allow(missing_docs)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, From)] pub enum AnyStringLiteral { StringLiteral(StringLiteral), MacroStringLiteral(MacroStringLiteral), } impl SourceElement for AnyStringLiteral { fn span(&self) -> Span { match self { Self::StringLiteral(string_literal) => string_literal.span(), Self::MacroStringLiteral(macro_string_literal) => macro_string_literal.span(), } } } impl<'a> Parser<'a> { /// Parses a list of elements enclosed by a pair of delimiters, separated by a separator. /// /// The parser position must be at the delimited list of the given delimiter. It will /// consume the whole delimited list and move the next token after the list. /// /// # Errors /// - if the parser position is not at the delimited list of the given delimiter. /// - any error returned by the given parser function. pub fn parse_enclosed_list( &mut self, delimiter: Delimiter, separator: char, mut f: impl FnMut(&mut Self) -> ParseResult, handler: &impl Handler, ) -> ParseResult> { fn skip_to_next_separator(this: &mut Parser, separator: char) -> Option { if let Reading::Atomic(Token::Punctuation(punc)) = this.stop_at(|token| { matches!( token, Reading::Atomic(Token::Punctuation(punc)) if punc.punctuation == separator ) }) { this.forward(); Some(punc) } else { None } } let delimited_tree = self.step_into( delimiter, |parser| { let mut first = None; let mut rest = Vec::new(); let mut trailing_separator: Option = None; while !parser.is_exhausted() { let Ok(element) = f(parser) else { skip_to_next_separator(parser, separator); continue; }; // adds new element match (&first, &trailing_separator) { (None, None) => { first = Some(element); } (Some(_), Some(separator)) => { rest.push((separator.clone(), element)); trailing_separator = None; } _ => { unreachable!() } } // expect separator if not exhausted if !parser.is_exhausted() { let Ok(separator) = parser.parse_punctuation(separator, true, handler) else { if let Some(punctuation) = skip_to_next_separator(parser, separator) { trailing_separator = Some(punctuation); } continue; }; trailing_separator = Some(separator); } } Ok(first.map(|first| ConnectedList { first, rest, trailing_separator, })) }, handler, )?; Ok(DelimitedList { open: delimited_tree.open, list: delimited_tree.tree.unwrap(), close: delimited_tree.close, }) } /// Parses a list of elements separated by a separator. /// /// The parser position must be at the connected list of the first element. It will /// consume the whole connected list and move the next token after the list. /// /// # Errors /// - if the parser position is not at the connected list of the given element. /// - any error returned by the given parser function. pub fn parse_connected_list( &mut self, seperator: char, mut f: impl FnMut(&mut Self) -> ParseResult, _handler: &impl Handler, ) -> ParseResult> { let first = f(self)?; let mut rest = Vec::new(); while let Ok(sep) = self.try_parse(|parser| parser.parse_punctuation(seperator, true, &VoidHandler)) { if let Ok(element) = self.try_parse(&mut f) { rest.push((sep, element)); } else { return Ok(ConnectedList { first, rest, trailing_separator: Some(sep), }); } } Ok(ConnectedList { first, rest, trailing_separator: None, }) } } impl SourceElement for ConnectedList { fn span(&self) -> Span { let end = self.trailing_separator.as_ref().map_or_else( || { self.rest .last() .map_or_else(|| self.first.span(), |(_, element)| element.span()) }, SourceElement::span, ); self.first.span().join(&end).unwrap() } } impl ConnectedList { /// Returns an iterator over the elements of the list. pub fn elements(&self) -> impl Iterator { std::iter::once(&self.first).chain(self.rest.iter().map(|(_, element)| element)) } /// Returns an iterator over the elements of the list. pub fn into_elements(self) -> impl Iterator { std::iter::once(self.first).chain(self.rest.into_iter().map(|(_, element)| element)) } /// Gets the number of elements in the list. pub fn len(&self) -> usize { self.rest.len() + 1 } /// Returns `true` if the list is empty. /// /// The function will never return `false`. pub fn is_empty(&self) -> bool { false } }