change return type of parse_* functions from Option to Result
This commit is contained in:
		
							parent
							
								
									2bc8281f19
								
							
						
					
					
						commit
						0cccee936e
					
				| 
						 | 
					@ -89,9 +89,7 @@ pub fn parse(
 | 
				
			||||||
    tracing::info!("Parsing the source code at path: {}", path.display());
 | 
					    tracing::info!("Parsing the source code at path: {}", path.display());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let mut parser = Parser::new(&tokens);
 | 
					    let mut parser = Parser::new(&tokens);
 | 
				
			||||||
    let program = parser
 | 
					    let program = parser.parse_program(handler)?;
 | 
				
			||||||
        .parse_program(handler)
 | 
					 | 
				
			||||||
        .ok_or_else(|| Error::other("An error occurred while parsing the source code."))?;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if handler.has_received() {
 | 
					    if handler.has_received() {
 | 
				
			||||||
        return Err(Error::other(
 | 
					        return Err(Error::other(
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,14 +3,31 @@
 | 
				
			||||||
use std::fmt::Display;
 | 
					use std::fmt::Display;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    base::log::{Message, Severity, SourceCodeDisplay},
 | 
					    base::{
 | 
				
			||||||
 | 
					        log::{Message, Severity, SourceCodeDisplay},
 | 
				
			||||||
 | 
					        source_file::Span,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    lexical::token::{KeywordKind, Token},
 | 
					    lexical::token::{KeywordKind, Token},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Result type for parsing operations.
 | 
				
			||||||
 | 
					pub type ParseResult<T> = Result<T, Error>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// An enumeration containing all kinds of syntactic errors that can occur while parsing the
 | 
				
			||||||
 | 
					#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, thiserror::Error)]
 | 
				
			||||||
 | 
					#[allow(missing_docs)]
 | 
				
			||||||
 | 
					pub enum Error {
 | 
				
			||||||
 | 
					    #[error(transparent)]
 | 
				
			||||||
 | 
					    UnexpectedSyntax(#[from] UnexpectedSyntax),
 | 
				
			||||||
 | 
					    #[error(transparent)]
 | 
				
			||||||
 | 
					    InvalidArgument(#[from] InvalidArgument),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Enumeration containing all kinds of syntax that can be failed to parse.
 | 
					/// Enumeration containing all kinds of syntax that can be failed to parse.
 | 
				
			||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
 | 
					#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
 | 
				
			||||||
#[allow(missing_docs)]
 | 
					#[allow(missing_docs)]
 | 
				
			||||||
pub enum SyntaxKind {
 | 
					pub enum SyntaxKind {
 | 
				
			||||||
 | 
					    Either(&'static [SyntaxKind]),
 | 
				
			||||||
    Punctuation(char),
 | 
					    Punctuation(char),
 | 
				
			||||||
    Keyword(KeywordKind),
 | 
					    Keyword(KeywordKind),
 | 
				
			||||||
    Identifier,
 | 
					    Identifier,
 | 
				
			||||||
| 
						 | 
					@ -24,6 +41,43 @@ pub enum SyntaxKind {
 | 
				
			||||||
    ExecuteBlockTail,
 | 
					    ExecuteBlockTail,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl SyntaxKind {
 | 
				
			||||||
 | 
					    fn expected_binding_str(&self) -> String {
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            Self::Either(variants) => {
 | 
				
			||||||
 | 
					                if variants.is_empty() {
 | 
				
			||||||
 | 
					                    "end of file".to_string()
 | 
				
			||||||
 | 
					                } else if variants.len() == 1 {
 | 
				
			||||||
 | 
					                    variants[0].expected_binding_str()
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    let comma_range = ..variants.len() - 2;
 | 
				
			||||||
 | 
					                    let comma_elements = variants[comma_range]
 | 
				
			||||||
 | 
					                        .iter()
 | 
				
			||||||
 | 
					                        .map(Self::expected_binding_str)
 | 
				
			||||||
 | 
					                        .collect::<Vec<_>>()
 | 
				
			||||||
 | 
					                        .join(", ");
 | 
				
			||||||
 | 
					                    format!(
 | 
				
			||||||
 | 
					                        "{}, or {}",
 | 
				
			||||||
 | 
					                        comma_elements,
 | 
				
			||||||
 | 
					                        variants.last().unwrap().expected_binding_str()
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            Self::Identifier => "an identifier token".to_string(),
 | 
				
			||||||
 | 
					            Self::Punctuation(char) => format!("a punctuation token `{char}`"),
 | 
				
			||||||
 | 
					            Self::Keyword(keyword) => format!("a keyword token `{}`", keyword.as_str()),
 | 
				
			||||||
 | 
					            Self::Declaration => "a declaration token".to_string(),
 | 
				
			||||||
 | 
					            Self::Numeric => "a numeric token".to_string(),
 | 
				
			||||||
 | 
					            Self::StringLiteral => "a string literal".to_string(),
 | 
				
			||||||
 | 
					            Self::Statement => "a statement syntax".to_string(),
 | 
				
			||||||
 | 
					            Self::Expression => "an expression syntax".to_string(),
 | 
				
			||||||
 | 
					            Self::Type => "a type syntax".to_string(),
 | 
				
			||||||
 | 
					            Self::ExecuteBlock => "an execute block syntax".to_string(),
 | 
				
			||||||
 | 
					            Self::ExecuteBlockTail => "an execute block tail syntax".to_string(),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// A syntax/token is expected but found an other invalid token.
 | 
					/// A syntax/token is expected but found an other invalid token.
 | 
				
			||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 | 
					#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 | 
				
			||||||
pub struct UnexpectedSyntax {
 | 
					pub struct UnexpectedSyntax {
 | 
				
			||||||
| 
						 | 
					@ -36,19 +90,7 @@ pub struct UnexpectedSyntax {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Display for UnexpectedSyntax {
 | 
					impl Display for UnexpectedSyntax {
 | 
				
			||||||
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
					    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
				
			||||||
        let expected_binding = match self.expected {
 | 
					        let expected_binding = self.expected.expected_binding_str();
 | 
				
			||||||
            SyntaxKind::Identifier => "an identifier token".to_string(),
 | 
					 | 
				
			||||||
            SyntaxKind::Punctuation(char) => format!("a punctuation token `{char}`"),
 | 
					 | 
				
			||||||
            SyntaxKind::Keyword(keyword) => format!("a keyword token `{}`", keyword.as_str()),
 | 
					 | 
				
			||||||
            SyntaxKind::Declaration => "a declaration token".to_string(),
 | 
					 | 
				
			||||||
            SyntaxKind::Numeric => "a numeric token".to_string(),
 | 
					 | 
				
			||||||
            SyntaxKind::StringLiteral => "a string literal".to_string(),
 | 
					 | 
				
			||||||
            SyntaxKind::Statement => "a statement syntax".to_string(),
 | 
					 | 
				
			||||||
            SyntaxKind::Expression => "an expression syntax".to_string(),
 | 
					 | 
				
			||||||
            SyntaxKind::Type => "a type syntax".to_string(),
 | 
					 | 
				
			||||||
            SyntaxKind::ExecuteBlock => "an execute block syntax".to_string(),
 | 
					 | 
				
			||||||
            SyntaxKind::ExecuteBlockTail => "an execute block tail syntax".to_string(),
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
        let found_binding = match self.found.clone() {
 | 
					        let found_binding = match self.found.clone() {
 | 
				
			||||||
            Some(Token::Comment(..)) => "a comment token".to_string(),
 | 
					            Some(Token::Comment(..)) => "a comment token".to_string(),
 | 
				
			||||||
            Some(Token::DocComment(..)) => "a doc comment token".to_string(),
 | 
					            Some(Token::DocComment(..)) => "a doc comment token".to_string(),
 | 
				
			||||||
| 
						 | 
					@ -83,10 +125,24 @@ impl Display for UnexpectedSyntax {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl std::error::Error for UnexpectedSyntax {}
 | 
					impl std::error::Error for UnexpectedSyntax {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// An enumeration containing all kinds of syntactic errors that can occur while parsing the
 | 
					/// An error that occurred due to an invalid argument.
 | 
				
			||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, thiserror::Error)]
 | 
					#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 | 
				
			||||||
#[allow(missing_docs)]
 | 
					pub struct InvalidArgument {
 | 
				
			||||||
pub enum Error {
 | 
					    /// The error message.
 | 
				
			||||||
    #[error(transparent)]
 | 
					    pub message: String,
 | 
				
			||||||
    UnexpectedSyntax(#[from] UnexpectedSyntax),
 | 
					    /// The span of the invalid argument.
 | 
				
			||||||
 | 
					    pub span: Span,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Display for InvalidArgument {
 | 
				
			||||||
 | 
					    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
				
			||||||
 | 
					        write!(f, "{}", Message::new(Severity::Error, &self.message))?;
 | 
				
			||||||
 | 
					        write!(
 | 
				
			||||||
 | 
					            f,
 | 
				
			||||||
 | 
					            "\n{}",
 | 
				
			||||||
 | 
					            SourceCodeDisplay::new(&self.span, Option::<u8>::None)
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl std::error::Error for InvalidArgument {}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,7 +11,7 @@ use crate::{
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use super::error::{Error, SyntaxKind, UnexpectedSyntax};
 | 
					use super::error::{Error, ParseResult, SyntaxKind, UnexpectedSyntax};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Represents a parser that reads a token stream and constructs an abstract syntax tree.
 | 
					/// Represents a parser that reads a token stream and constructs an abstract syntax tree.
 | 
				
			||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Deref, DerefMut)]
 | 
					#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Deref, DerefMut)]
 | 
				
			||||||
| 
						 | 
					@ -38,12 +38,15 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
    /// Steps into the [`Delimited`] token stream and parses the content within the delimiters.
 | 
					    /// Steps into the [`Delimited`] token stream and parses the content within the delimiters.
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// The parser's position must be at the delimited token stream.
 | 
					    /// The parser's position must be at the delimited token stream.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// # Errors
 | 
				
			||||||
 | 
					    /// - If the parser's position is not at the delimited token stream.
 | 
				
			||||||
    pub fn step_into<T>(
 | 
					    pub fn step_into<T>(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        delimiter: Delimiter,
 | 
					        delimiter: Delimiter,
 | 
				
			||||||
        f: impl FnOnce(&mut Self) -> Option<T>,
 | 
					        f: impl FnOnce(&mut Self) -> ParseResult<T>,
 | 
				
			||||||
        handler: &impl Handler<base::Error>,
 | 
					        handler: &impl Handler<base::Error>,
 | 
				
			||||||
    ) -> Option<DelimitedTree<T>> {
 | 
					    ) -> ParseResult<DelimitedTree<T>> {
 | 
				
			||||||
        self.current_frame.stop_at_significant();
 | 
					        self.current_frame.stop_at_significant();
 | 
				
			||||||
        let raw_token_tree = self
 | 
					        let raw_token_tree = self
 | 
				
			||||||
            .current_frame
 | 
					            .current_frame
 | 
				
			||||||
| 
						 | 
					@ -62,7 +65,7 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
                    delimited_tree
 | 
					                    delimited_tree
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                found => {
 | 
					                found => {
 | 
				
			||||||
                    handler.receive(Error::UnexpectedSyntax(UnexpectedSyntax {
 | 
					                    let err = Error::UnexpectedSyntax(UnexpectedSyntax {
 | 
				
			||||||
                        expected: SyntaxKind::Punctuation(expected),
 | 
					                        expected: SyntaxKind::Punctuation(expected),
 | 
				
			||||||
                        found: Some(match found {
 | 
					                        found: Some(match found {
 | 
				
			||||||
                            TokenTree::Token(token) => token.clone(),
 | 
					                            TokenTree::Token(token) => token.clone(),
 | 
				
			||||||
| 
						 | 
					@ -70,18 +73,20 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
                                Token::Punctuation(delimited_tree.open.clone())
 | 
					                                Token::Punctuation(delimited_tree.open.clone())
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                        }),
 | 
					                        }),
 | 
				
			||||||
                    }));
 | 
					                    });
 | 
				
			||||||
 | 
					                    handler.receive(err.clone());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    return None;
 | 
					                    return Err(err);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            handler.receive(Error::UnexpectedSyntax(UnexpectedSyntax {
 | 
					            let err = Error::UnexpectedSyntax(UnexpectedSyntax {
 | 
				
			||||||
                expected: SyntaxKind::Punctuation(expected),
 | 
					                expected: SyntaxKind::Punctuation(expected),
 | 
				
			||||||
                found: self.get_reading(None).into_token(),
 | 
					                found: self.get_reading(None).into_token(),
 | 
				
			||||||
            }));
 | 
					            });
 | 
				
			||||||
 | 
					            handler.receive(err.clone());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return None;
 | 
					            return Err(err);
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // creates a new frame
 | 
					        // creates a new frame
 | 
				
			||||||
| 
						 | 
					@ -99,7 +104,10 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
        let tree = f(self);
 | 
					        let tree = f(self);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // pops the current frame off the stack
 | 
					        // pops the current frame off the stack
 | 
				
			||||||
        let new_frame = self.stack.pop()?;
 | 
					        let new_frame = self
 | 
				
			||||||
 | 
					            .stack
 | 
				
			||||||
 | 
					            .pop()
 | 
				
			||||||
 | 
					            .expect("frame has been pushed on the stack before");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // the current frame must be at the end
 | 
					        // the current frame must be at the end
 | 
				
			||||||
        if !self.current_frame.is_exhausted() {
 | 
					        if !self.current_frame.is_exhausted() {
 | 
				
			||||||
| 
						 | 
					@ -111,10 +119,12 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
                .delimiter
 | 
					                .delimiter
 | 
				
			||||||
                .closing_char();
 | 
					                .closing_char();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            handler.receive(Error::UnexpectedSyntax(UnexpectedSyntax {
 | 
					            let err = Error::UnexpectedSyntax(UnexpectedSyntax {
 | 
				
			||||||
                expected: SyntaxKind::Punctuation(expected),
 | 
					                expected: SyntaxKind::Punctuation(expected),
 | 
				
			||||||
                found: self.peek().into_token(),
 | 
					                found: self.peek().into_token(),
 | 
				
			||||||
            }));
 | 
					            });
 | 
				
			||||||
 | 
					            handler.receive(err.clone());
 | 
				
			||||||
 | 
					            return Err(err);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let close_punctuation = self
 | 
					        let close_punctuation = self
 | 
				
			||||||
| 
						 | 
					@ -128,7 +138,7 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
        // replaces the current frame with the popped one
 | 
					        // replaces the current frame with the popped one
 | 
				
			||||||
        self.current_frame = new_frame;
 | 
					        self.current_frame = new_frame;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Some(DelimitedTree {
 | 
					        Ok(DelimitedTree {
 | 
				
			||||||
            open,
 | 
					            open,
 | 
				
			||||||
            tree,
 | 
					            tree,
 | 
				
			||||||
            close: close_punctuation,
 | 
					            close: close_punctuation,
 | 
				
			||||||
| 
						 | 
					@ -137,12 +147,15 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Tries to parse the given function, and if it fails, resets the current index to the
 | 
					    /// Tries to parse the given function, and if it fails, resets the current index to the
 | 
				
			||||||
    /// `current_index` before the function call.
 | 
					    /// `current_index` before the function call.
 | 
				
			||||||
    pub fn try_parse<T>(&mut self, f: impl FnOnce(&mut Self) -> Option<T>) -> Option<T> {
 | 
					    ///
 | 
				
			||||||
 | 
					    /// # Errors
 | 
				
			||||||
 | 
					    /// - If the given function returns an error.
 | 
				
			||||||
 | 
					    pub fn try_parse<T>(&mut self, f: impl FnOnce(&mut Self) -> ParseResult<T>) -> ParseResult<T> {
 | 
				
			||||||
        let current_index = self.current_frame.current_index;
 | 
					        let current_index = self.current_frame.current_index;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let result = f(self);
 | 
					        let result = f(self);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if result.is_none() {
 | 
					        if result.is_err() {
 | 
				
			||||||
            self.current_frame.current_index = current_index;
 | 
					            self.current_frame.current_index = current_index;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -157,7 +170,7 @@ pub struct DelimitedTree<T> {
 | 
				
			||||||
    pub open: Punctuation,
 | 
					    pub open: Punctuation,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// The tree inside the delimiter.
 | 
					    /// The tree inside the delimiter.
 | 
				
			||||||
    pub tree: Option<T>,
 | 
					    pub tree: ParseResult<T>,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// The closing delimiter.
 | 
					    /// The closing delimiter.
 | 
				
			||||||
    pub close: Punctuation,
 | 
					    pub close: Punctuation,
 | 
				
			||||||
| 
						 | 
					@ -363,15 +376,19 @@ impl<'a> Frame<'a> {
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// # Errors
 | 
					    /// # Errors
 | 
				
			||||||
    /// If the next [`Token`] is not an [`Identifier`].
 | 
					    /// If the next [`Token`] is not an [`Identifier`].
 | 
				
			||||||
    pub fn parse_identifier(&mut self, handler: &impl Handler<base::Error>) -> Option<Identifier> {
 | 
					    pub fn parse_identifier(
 | 
				
			||||||
 | 
					        &mut self,
 | 
				
			||||||
 | 
					        handler: &impl Handler<base::Error>,
 | 
				
			||||||
 | 
					    ) -> ParseResult<Identifier> {
 | 
				
			||||||
        match self.next_significant_token() {
 | 
					        match self.next_significant_token() {
 | 
				
			||||||
            Reading::Atomic(Token::Identifier(ident)) => Some(ident),
 | 
					            Reading::Atomic(Token::Identifier(ident)) => Ok(ident),
 | 
				
			||||||
            found => {
 | 
					            found => {
 | 
				
			||||||
                handler.receive(Error::UnexpectedSyntax(UnexpectedSyntax {
 | 
					                let err = Error::UnexpectedSyntax(UnexpectedSyntax {
 | 
				
			||||||
                    expected: SyntaxKind::Identifier,
 | 
					                    expected: SyntaxKind::Identifier,
 | 
				
			||||||
                    found: found.into_token(),
 | 
					                    found: found.into_token(),
 | 
				
			||||||
                }));
 | 
					                });
 | 
				
			||||||
                None
 | 
					                handler.receive(err.clone());
 | 
				
			||||||
 | 
					                Err(err)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -380,15 +397,16 @@ impl<'a> Frame<'a> {
 | 
				
			||||||
    ///
 | 
					    ///
 | 
				
			||||||
    /// # Errors
 | 
					    /// # Errors
 | 
				
			||||||
    /// If the next [`Token`] is not an [`Identifier`].
 | 
					    /// If the next [`Token`] is not an [`Identifier`].
 | 
				
			||||||
    pub fn parse_numeric(&mut self, handler: &impl Handler<Error>) -> Option<Numeric> {
 | 
					    pub fn parse_numeric(&mut self, handler: &impl Handler<Error>) -> ParseResult<Numeric> {
 | 
				
			||||||
        match self.next_significant_token() {
 | 
					        match self.next_significant_token() {
 | 
				
			||||||
            Reading::Atomic(Token::Numeric(ident)) => Some(ident),
 | 
					            Reading::Atomic(Token::Numeric(ident)) => Ok(ident),
 | 
				
			||||||
            found => {
 | 
					            found => {
 | 
				
			||||||
                handler.receive(Error::UnexpectedSyntax(UnexpectedSyntax {
 | 
					                let err = Error::UnexpectedSyntax(UnexpectedSyntax {
 | 
				
			||||||
                    expected: SyntaxKind::Numeric,
 | 
					                    expected: SyntaxKind::Numeric,
 | 
				
			||||||
                    found: found.into_token(),
 | 
					                    found: found.into_token(),
 | 
				
			||||||
                }));
 | 
					                });
 | 
				
			||||||
                None
 | 
					                handler.receive(err.clone());
 | 
				
			||||||
 | 
					                Err(err)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -400,15 +418,16 @@ impl<'a> Frame<'a> {
 | 
				
			||||||
    pub fn parse_string_literal(
 | 
					    pub fn parse_string_literal(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        handler: &impl Handler<base::Error>,
 | 
					        handler: &impl Handler<base::Error>,
 | 
				
			||||||
    ) -> Option<StringLiteral> {
 | 
					    ) -> ParseResult<StringLiteral> {
 | 
				
			||||||
        match self.next_significant_token() {
 | 
					        match self.next_significant_token() {
 | 
				
			||||||
            Reading::Atomic(Token::StringLiteral(literal)) => Some(literal),
 | 
					            Reading::Atomic(Token::StringLiteral(literal)) => Ok(literal),
 | 
				
			||||||
            found => {
 | 
					            found => {
 | 
				
			||||||
                handler.receive(Error::UnexpectedSyntax(UnexpectedSyntax {
 | 
					                let err = Error::UnexpectedSyntax(UnexpectedSyntax {
 | 
				
			||||||
                    expected: SyntaxKind::StringLiteral,
 | 
					                    expected: SyntaxKind::StringLiteral,
 | 
				
			||||||
                    found: found.into_token(),
 | 
					                    found: found.into_token(),
 | 
				
			||||||
                }));
 | 
					                });
 | 
				
			||||||
                None
 | 
					                handler.receive(err.clone());
 | 
				
			||||||
 | 
					                Err(err)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -421,17 +440,18 @@ impl<'a> Frame<'a> {
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        expected: KeywordKind,
 | 
					        expected: KeywordKind,
 | 
				
			||||||
        handler: &impl Handler<base::Error>,
 | 
					        handler: &impl Handler<base::Error>,
 | 
				
			||||||
    ) -> Option<Keyword> {
 | 
					    ) -> ParseResult<Keyword> {
 | 
				
			||||||
        match self.next_significant_token() {
 | 
					        match self.next_significant_token() {
 | 
				
			||||||
            Reading::Atomic(Token::Keyword(keyword_token)) if keyword_token.keyword == expected => {
 | 
					            Reading::Atomic(Token::Keyword(keyword_token)) if keyword_token.keyword == expected => {
 | 
				
			||||||
                Some(keyword_token)
 | 
					                Ok(keyword_token)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            found => {
 | 
					            found => {
 | 
				
			||||||
                handler.receive(Error::UnexpectedSyntax(UnexpectedSyntax {
 | 
					                let err = Error::UnexpectedSyntax(UnexpectedSyntax {
 | 
				
			||||||
                    expected: SyntaxKind::Keyword(expected),
 | 
					                    expected: SyntaxKind::Keyword(expected),
 | 
				
			||||||
                    found: found.into_token(),
 | 
					                    found: found.into_token(),
 | 
				
			||||||
                }));
 | 
					                });
 | 
				
			||||||
                None
 | 
					                handler.receive(err.clone());
 | 
				
			||||||
 | 
					                Err(err)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -445,7 +465,7 @@ impl<'a> Frame<'a> {
 | 
				
			||||||
        expected: char,
 | 
					        expected: char,
 | 
				
			||||||
        skip_insignificant: bool,
 | 
					        skip_insignificant: bool,
 | 
				
			||||||
        handler: &impl Handler<base::Error>,
 | 
					        handler: &impl Handler<base::Error>,
 | 
				
			||||||
    ) -> Option<Punctuation> {
 | 
					    ) -> ParseResult<Punctuation> {
 | 
				
			||||||
        match if skip_insignificant {
 | 
					        match if skip_insignificant {
 | 
				
			||||||
            self.next_significant_token()
 | 
					            self.next_significant_token()
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
| 
						 | 
					@ -454,14 +474,15 @@ impl<'a> Frame<'a> {
 | 
				
			||||||
            Reading::Atomic(Token::Punctuation(punctuation_token))
 | 
					            Reading::Atomic(Token::Punctuation(punctuation_token))
 | 
				
			||||||
                if punctuation_token.punctuation == expected =>
 | 
					                if punctuation_token.punctuation == expected =>
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                Some(punctuation_token)
 | 
					                Ok(punctuation_token)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            found => {
 | 
					            found => {
 | 
				
			||||||
                handler.receive(Error::UnexpectedSyntax(UnexpectedSyntax {
 | 
					                let err = Error::UnexpectedSyntax(UnexpectedSyntax {
 | 
				
			||||||
                    expected: SyntaxKind::Punctuation(expected),
 | 
					                    expected: SyntaxKind::Punctuation(expected),
 | 
				
			||||||
                    found: found.into_token(),
 | 
					                    found: found.into_token(),
 | 
				
			||||||
                }));
 | 
					                });
 | 
				
			||||||
                None
 | 
					                handler.receive(err.clone());
 | 
				
			||||||
 | 
					                Err(err)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,7 @@
 | 
				
			||||||
//! Syntax tree nodes for conditions.
 | 
					//! Syntax tree nodes for conditions.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#![allow(clippy::missing_errors_doc)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use std::{cmp::Ordering, collections::VecDeque};
 | 
					use std::{cmp::Ordering, collections::VecDeque};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use enum_as_inner::EnumAsInner;
 | 
					use enum_as_inner::EnumAsInner;
 | 
				
			||||||
| 
						 | 
					@ -9,14 +11,14 @@ use crate::{
 | 
				
			||||||
    base::{
 | 
					    base::{
 | 
				
			||||||
        self,
 | 
					        self,
 | 
				
			||||||
        source_file::{SourceElement, Span},
 | 
					        source_file::{SourceElement, Span},
 | 
				
			||||||
        VoidHandler, Handler,
 | 
					        Handler, VoidHandler,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    lexical::{
 | 
					    lexical::{
 | 
				
			||||||
        token::{Punctuation, StringLiteral, Token},
 | 
					        token::{Punctuation, StringLiteral, Token},
 | 
				
			||||||
        token_stream::Delimiter,
 | 
					        token_stream::Delimiter,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    syntax::{
 | 
					    syntax::{
 | 
				
			||||||
        error::{Error, SyntaxKind, UnexpectedSyntax},
 | 
					        error::{Error, ParseResult, SyntaxKind, UnexpectedSyntax},
 | 
				
			||||||
        parser::{Parser, Reading},
 | 
					        parser::{Parser, Reading},
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -241,12 +243,20 @@ impl SourceElement for Condition {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<'a> Parser<'a> {
 | 
					impl<'a> Parser<'a> {
 | 
				
			||||||
    /// Parses a [`Condition`].
 | 
					    /// Parses a [`Condition`].
 | 
				
			||||||
    pub fn parse_condition(&mut self, handler: &impl Handler<base::Error>) -> Option<Condition> {
 | 
					    ///
 | 
				
			||||||
 | 
					    /// # Precedence of the operators
 | 
				
			||||||
 | 
					    /// 1. `!`
 | 
				
			||||||
 | 
					    /// 2. `&&`
 | 
				
			||||||
 | 
					    /// 3. `||`
 | 
				
			||||||
 | 
					    pub fn parse_condition(
 | 
				
			||||||
 | 
					        &mut self,
 | 
				
			||||||
 | 
					        handler: &impl Handler<base::Error>,
 | 
				
			||||||
 | 
					    ) -> ParseResult<Condition> {
 | 
				
			||||||
        let mut lhs = Condition::Primary(self.parse_primary_condition(handler)?);
 | 
					        let mut lhs = Condition::Primary(self.parse_primary_condition(handler)?);
 | 
				
			||||||
        let mut expressions = VecDeque::new();
 | 
					        let mut expressions = VecDeque::new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Parses a list of binary operators and expressions
 | 
					        // Parses a list of binary operators and expressions
 | 
				
			||||||
        while let Some(binary_operator) = self.try_parse_conditional_binary_operator() {
 | 
					        while let Ok(binary_operator) = self.try_parse_conditional_binary_operator() {
 | 
				
			||||||
            expressions.push_back((
 | 
					            expressions.push_back((
 | 
				
			||||||
                binary_operator,
 | 
					                binary_operator,
 | 
				
			||||||
                Some(Condition::Primary(self.parse_primary_condition(handler)?)),
 | 
					                Some(Condition::Primary(self.parse_primary_condition(handler)?)),
 | 
				
			||||||
| 
						 | 
					@ -300,14 +310,14 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Some(lhs)
 | 
					        Ok(lhs)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Parses a [`PrimaryCondition`].
 | 
					    /// Parses a [`PrimaryCondition`].
 | 
				
			||||||
    pub fn parse_primary_condition(
 | 
					    pub fn parse_primary_condition(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        handler: &impl Handler<base::Error>,
 | 
					        handler: &impl Handler<base::Error>,
 | 
				
			||||||
    ) -> Option<PrimaryCondition> {
 | 
					    ) -> ParseResult<PrimaryCondition> {
 | 
				
			||||||
        match self.stop_at_significant() {
 | 
					        match self.stop_at_significant() {
 | 
				
			||||||
            // prefixed expression
 | 
					            // prefixed expression
 | 
				
			||||||
            Reading::Atomic(Token::Punctuation(punc)) if punc.punctuation == '!' => {
 | 
					            Reading::Atomic(Token::Punctuation(punc)) if punc.punctuation == '!' => {
 | 
				
			||||||
| 
						 | 
					@ -321,7 +331,7 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                let operand = Box::new(self.parse_primary_condition(handler)?);
 | 
					                let operand = Box::new(self.parse_primary_condition(handler)?);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Some(PrimaryCondition::Prefix(ConditionalPrefix {
 | 
					                Ok(PrimaryCondition::Prefix(ConditionalPrefix {
 | 
				
			||||||
                    operator,
 | 
					                    operator,
 | 
				
			||||||
                    operand,
 | 
					                    operand,
 | 
				
			||||||
                }))
 | 
					                }))
 | 
				
			||||||
| 
						 | 
					@ -330,7 +340,7 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
            // string literal
 | 
					            // string literal
 | 
				
			||||||
            Reading::Atomic(Token::StringLiteral(literal)) => {
 | 
					            Reading::Atomic(Token::StringLiteral(literal)) => {
 | 
				
			||||||
                self.forward();
 | 
					                self.forward();
 | 
				
			||||||
                Some(PrimaryCondition::StringLiteral(literal))
 | 
					                Ok(PrimaryCondition::StringLiteral(literal))
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // parenthesized condition
 | 
					            // parenthesized condition
 | 
				
			||||||
| 
						 | 
					@ -342,12 +352,17 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
                // make progress
 | 
					                // make progress
 | 
				
			||||||
                self.forward();
 | 
					                self.forward();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                handler.receive(Error::UnexpectedSyntax(UnexpectedSyntax {
 | 
					                let err = Error::UnexpectedSyntax(UnexpectedSyntax {
 | 
				
			||||||
                    expected: SyntaxKind::Expression,
 | 
					                    expected: SyntaxKind::Either(&[
 | 
				
			||||||
 | 
					                        SyntaxKind::Punctuation('!'),
 | 
				
			||||||
 | 
					                        SyntaxKind::StringLiteral,
 | 
				
			||||||
 | 
					                        SyntaxKind::Punctuation('('),
 | 
				
			||||||
 | 
					                    ]),
 | 
				
			||||||
                    found: unexpected.into_token(),
 | 
					                    found: unexpected.into_token(),
 | 
				
			||||||
                }));
 | 
					                });
 | 
				
			||||||
 | 
					                handler.receive(err.clone());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                None
 | 
					                Err(err)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -356,38 +371,59 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
    pub fn parse_parenthesized_condition(
 | 
					    pub fn parse_parenthesized_condition(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        handler: &impl Handler<base::Error>,
 | 
					        handler: &impl Handler<base::Error>,
 | 
				
			||||||
    ) -> Option<ParenthesizedCondition> {
 | 
					    ) -> ParseResult<ParenthesizedCondition> {
 | 
				
			||||||
        let token_tree = self.step_into(
 | 
					        let token_tree = self.step_into(
 | 
				
			||||||
            Delimiter::Parenthesis,
 | 
					            Delimiter::Parenthesis,
 | 
				
			||||||
            |parser| {
 | 
					            |parser| {
 | 
				
			||||||
                let cond = parser.parse_condition(handler)?;
 | 
					                let cond = parser.parse_condition(handler)?;
 | 
				
			||||||
                parser.stop_at_significant();
 | 
					                parser.stop_at_significant();
 | 
				
			||||||
                Some(cond)
 | 
					                Ok(cond)
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            handler,
 | 
					            handler,
 | 
				
			||||||
        )?;
 | 
					        )?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Some(ParenthesizedCondition {
 | 
					        Ok(ParenthesizedCondition {
 | 
				
			||||||
            open_paren: token_tree.open,
 | 
					            open_paren: token_tree.open,
 | 
				
			||||||
            condition: Box::new(token_tree.tree?),
 | 
					            condition: Box::new(token_tree.tree?),
 | 
				
			||||||
            close_paren: token_tree.close,
 | 
					            close_paren: token_tree.close,
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn try_parse_conditional_binary_operator(&mut self) -> Option<ConditionalBinaryOperator> {
 | 
					    fn try_parse_conditional_binary_operator(&mut self) -> ParseResult<ConditionalBinaryOperator> {
 | 
				
			||||||
        self.try_parse(|parser| match parser.next_significant_token() {
 | 
					        self.try_parse(|parser| match parser.next_significant_token() {
 | 
				
			||||||
            Reading::Atomic(Token::Punctuation(punc)) => match punc.punctuation {
 | 
					            Reading::Atomic(token) => match token.clone() {
 | 
				
			||||||
 | 
					                Token::Punctuation(punc) => match punc.punctuation {
 | 
				
			||||||
                    '&' => {
 | 
					                    '&' => {
 | 
				
			||||||
                        let b = parser.parse_punctuation('&', false, &VoidHandler)?;
 | 
					                        let b = parser.parse_punctuation('&', false, &VoidHandler)?;
 | 
				
			||||||
                    Some(ConditionalBinaryOperator::LogicalAnd(punc, b))
 | 
					                        Ok(ConditionalBinaryOperator::LogicalAnd(punc, b))
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    '|' => {
 | 
					                    '|' => {
 | 
				
			||||||
                        let b = parser.parse_punctuation('|', false, &VoidHandler)?;
 | 
					                        let b = parser.parse_punctuation('|', false, &VoidHandler)?;
 | 
				
			||||||
                    Some(ConditionalBinaryOperator::LogicalOr(punc, b))
 | 
					                        Ok(ConditionalBinaryOperator::LogicalOr(punc, b))
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                _ => None,
 | 
					                    _ => Err(Error::UnexpectedSyntax(UnexpectedSyntax {
 | 
				
			||||||
 | 
					                        expected: SyntaxKind::Either(&[
 | 
				
			||||||
 | 
					                            SyntaxKind::Punctuation('&'),
 | 
				
			||||||
 | 
					                            SyntaxKind::Punctuation('|'),
 | 
				
			||||||
 | 
					                        ]),
 | 
				
			||||||
 | 
					                        found: Some(token),
 | 
				
			||||||
 | 
					                    })),
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
            _ => None,
 | 
					                unexpected => Err(Error::UnexpectedSyntax(UnexpectedSyntax {
 | 
				
			||||||
 | 
					                    expected: SyntaxKind::Either(&[
 | 
				
			||||||
 | 
					                        SyntaxKind::Punctuation('&'),
 | 
				
			||||||
 | 
					                        SyntaxKind::Punctuation('|'),
 | 
				
			||||||
 | 
					                    ]),
 | 
				
			||||||
 | 
					                    found: Some(unexpected),
 | 
				
			||||||
 | 
					                })),
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            unexpected => Err(Error::UnexpectedSyntax(UnexpectedSyntax {
 | 
				
			||||||
 | 
					                expected: SyntaxKind::Either(&[
 | 
				
			||||||
 | 
					                    SyntaxKind::Punctuation('&'),
 | 
				
			||||||
 | 
					                    SyntaxKind::Punctuation('|'),
 | 
				
			||||||
 | 
					                ]),
 | 
				
			||||||
 | 
					                found: unexpected.into_token(),
 | 
				
			||||||
 | 
					            })),
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,7 +15,7 @@ use crate::{
 | 
				
			||||||
        token_stream::Delimiter,
 | 
					        token_stream::Delimiter,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    syntax::{
 | 
					    syntax::{
 | 
				
			||||||
        error::{Error, SyntaxKind, UnexpectedSyntax},
 | 
					        error::{Error, ParseResult, SyntaxKind, UnexpectedSyntax},
 | 
				
			||||||
        parser::{Parser, Reading},
 | 
					        parser::{Parser, Reading},
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -227,7 +227,15 @@ impl SourceElement for Import {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<'a> Parser<'a> {
 | 
					impl<'a> Parser<'a> {
 | 
				
			||||||
    pub fn parse_annotation(&mut self, handler: &impl Handler<base::Error>) -> Option<Annotation> {
 | 
					    /// Parses an annotation.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// # Errors
 | 
				
			||||||
 | 
					    /// - if the parser position is not at an annotation.
 | 
				
			||||||
 | 
					    /// - if the parsing of the annotation fails
 | 
				
			||||||
 | 
					    pub fn parse_annotation(
 | 
				
			||||||
 | 
					        &mut self,
 | 
				
			||||||
 | 
					        handler: &impl Handler<base::Error>,
 | 
				
			||||||
 | 
					    ) -> ParseResult<Annotation> {
 | 
				
			||||||
        match self.stop_at_significant() {
 | 
					        match self.stop_at_significant() {
 | 
				
			||||||
            Reading::Atomic(Token::Punctuation(punctuation)) if punctuation.punctuation == '#' => {
 | 
					            Reading::Atomic(Token::Punctuation(punctuation)) if punctuation.punctuation == '#' => {
 | 
				
			||||||
                // eat the pound sign
 | 
					                // eat the pound sign
 | 
				
			||||||
| 
						 | 
					@ -239,36 +247,29 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
                    |parser| {
 | 
					                    |parser| {
 | 
				
			||||||
                        let identifier = parser.parse_identifier(handler)?;
 | 
					                        let identifier = parser.parse_identifier(handler)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        let value = if let Reading::Atomic(Token::Punctuation(punctuation)) =
 | 
					                        let value = match parser.stop_at_significant() {
 | 
				
			||||||
                            parser.stop_at_significant()
 | 
					                            Reading::Atomic(Token::Punctuation(punc))
 | 
				
			||||||
 | 
					                                if punc.punctuation == '=' =>
 | 
				
			||||||
                            {
 | 
					                            {
 | 
				
			||||||
                            if punctuation.punctuation == '=' {
 | 
					 | 
				
			||||||
                                // eat the equals sign
 | 
					                                // eat the equals sign
 | 
				
			||||||
                                parser.forward();
 | 
					                                parser.forward();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                // parse the string literal
 | 
					                                // parse the string literal
 | 
				
			||||||
                                let string_literal = parser
 | 
					                                let string_literal = parser.parse_string_literal(handler)?;
 | 
				
			||||||
                                    .next_significant_token()
 | 
					 | 
				
			||||||
                                    .into_token()?
 | 
					 | 
				
			||||||
                                    .into_string_literal()
 | 
					 | 
				
			||||||
                                    .ok()?;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                Some((punctuation, string_literal))
 | 
					                                Some((punc, string_literal))
 | 
				
			||||||
                            } else {
 | 
					 | 
				
			||||||
                                None
 | 
					 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                        } else {
 | 
					                            _ => None,
 | 
				
			||||||
                            None
 | 
					 | 
				
			||||||
                        };
 | 
					                        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        Some((identifier, value))
 | 
					                        Ok((identifier, value))
 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
                    handler,
 | 
					                    handler,
 | 
				
			||||||
                )?;
 | 
					                )?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                let (identifier, value) = content.tree?;
 | 
					                let (identifier, value) = content.tree?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Some(Annotation {
 | 
					                Ok(Annotation {
 | 
				
			||||||
                    pound_sign: punctuation,
 | 
					                    pound_sign: punctuation,
 | 
				
			||||||
                    open_bracket: content.open,
 | 
					                    open_bracket: content.open,
 | 
				
			||||||
                    identifier,
 | 
					                    identifier,
 | 
				
			||||||
| 
						 | 
					@ -276,7 +277,14 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
                    close_bracket: content.close,
 | 
					                    close_bracket: content.close,
 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            _ => None,
 | 
					            unexpected => {
 | 
				
			||||||
 | 
					                let err = Error::UnexpectedSyntax(UnexpectedSyntax {
 | 
				
			||||||
 | 
					                    expected: SyntaxKind::Punctuation('#'),
 | 
				
			||||||
 | 
					                    found: unexpected.into_token(),
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					                handler.receive(err.clone());
 | 
				
			||||||
 | 
					                Err(err)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -284,7 +292,7 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
    pub fn parse_declaration(
 | 
					    pub fn parse_declaration(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        handler: &impl Handler<base::Error>,
 | 
					        handler: &impl Handler<base::Error>,
 | 
				
			||||||
    ) -> Option<Declaration> {
 | 
					    ) -> ParseResult<Declaration> {
 | 
				
			||||||
        match self.stop_at_significant() {
 | 
					        match self.stop_at_significant() {
 | 
				
			||||||
            Reading::Atomic(Token::Keyword(function_keyword))
 | 
					            Reading::Atomic(Token::Keyword(function_keyword))
 | 
				
			||||||
                if function_keyword.keyword == KeywordKind::Function =>
 | 
					                if function_keyword.keyword == KeywordKind::Function =>
 | 
				
			||||||
| 
						 | 
					@ -293,22 +301,17 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                tracing::trace!("Parsed function '{:?}'", function.identifier.span.str());
 | 
					                tracing::trace!("Parsed function '{:?}'", function.identifier.span.str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Some(Declaration::Function(function))
 | 
					                Ok(Declaration::Function(function))
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Reading::Atomic(Token::Keyword(pub_keyword))
 | 
					            Reading::Atomic(Token::Keyword(pub_keyword))
 | 
				
			||||||
                if pub_keyword.keyword == KeywordKind::Pub =>
 | 
					                if pub_keyword.keyword == KeywordKind::Pub =>
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                // eat the public keyword
 | 
					 | 
				
			||||||
                self.forward();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                // parse the function keyword
 | 
					 | 
				
			||||||
                let function = self.parse_function(handler)?;
 | 
					                let function = self.parse_function(handler)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Some(Declaration::Function(Function {
 | 
					                tracing::trace!("Parsed function '{:?}'", function.identifier.span.str());
 | 
				
			||||||
                    public_keyword: Some(pub_keyword),
 | 
					
 | 
				
			||||||
                    ..function
 | 
					                Ok(Declaration::Function(function))
 | 
				
			||||||
                }))
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // parse annotations
 | 
					            // parse annotations
 | 
				
			||||||
| 
						 | 
					@ -316,23 +319,15 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
                // parse the annotation
 | 
					                // parse the annotation
 | 
				
			||||||
                let mut annotations = Vec::new();
 | 
					                let mut annotations = Vec::new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                while let Some(annotation) =
 | 
					                while let Ok(annotation) =
 | 
				
			||||||
                    self.try_parse(|parser| parser.parse_annotation(handler))
 | 
					                    self.try_parse(|parser| parser.parse_annotation(&VoidHandler))
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    annotations.push(annotation);
 | 
					                    annotations.push(annotation);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                self.parse_declaration(handler).and_then(|declaration| {
 | 
					                self.parse_function(handler).map(|mut function| {
 | 
				
			||||||
                    if let Declaration::Function(mut function) = declaration {
 | 
					 | 
				
			||||||
                    function.annotations.extend(annotations);
 | 
					                    function.annotations.extend(annotations);
 | 
				
			||||||
                        Some(Declaration::Function(function))
 | 
					                    Declaration::Function(function)
 | 
				
			||||||
                    } else {
 | 
					 | 
				
			||||||
                        handler.receive(Error::UnexpectedSyntax(UnexpectedSyntax {
 | 
					 | 
				
			||||||
                            expected: SyntaxKind::Keyword(KeywordKind::Function),
 | 
					 | 
				
			||||||
                            found: None,
 | 
					 | 
				
			||||||
                        }));
 | 
					 | 
				
			||||||
                        None
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -366,12 +361,12 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
                // }
 | 
					                // }
 | 
				
			||||||
                ;
 | 
					                ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if let Some(items) = items {
 | 
					                if let Ok(items) = items {
 | 
				
			||||||
                    let semicolon = self.parse_punctuation(';', true, handler)?;
 | 
					                    let semicolon = self.parse_punctuation(';', true, handler)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    tracing::trace!("Parsed import from '{:?}'", module.str_content());
 | 
					                    tracing::trace!("Parsed import from '{:?}'", module.str_content());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    Some(Declaration::Import(Import {
 | 
					                    Ok(Declaration::Import(Import {
 | 
				
			||||||
                        from_keyword,
 | 
					                        from_keyword,
 | 
				
			||||||
                        module,
 | 
					                        module,
 | 
				
			||||||
                        import_keyword,
 | 
					                        import_keyword,
 | 
				
			||||||
| 
						 | 
					@ -379,12 +374,13 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
                        semicolon,
 | 
					                        semicolon,
 | 
				
			||||||
                    }))
 | 
					                    }))
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    handler.receive(Error::UnexpectedSyntax(UnexpectedSyntax {
 | 
					                    let err = Error::UnexpectedSyntax(UnexpectedSyntax {
 | 
				
			||||||
                        expected: SyntaxKind::Identifier,
 | 
					                        expected: SyntaxKind::Punctuation('*'),
 | 
				
			||||||
                        found: self.stop_at_significant().into_token(),
 | 
					                        found: self.stop_at_significant().into_token(),
 | 
				
			||||||
                    }));
 | 
					                    });
 | 
				
			||||||
 | 
					                    handler.receive(err.clone());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    None
 | 
					                    Err(err)
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -392,18 +388,30 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
                // make progress
 | 
					                // make progress
 | 
				
			||||||
                self.forward();
 | 
					                self.forward();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                handler.receive(Error::UnexpectedSyntax(UnexpectedSyntax {
 | 
					                let err = Error::UnexpectedSyntax(UnexpectedSyntax {
 | 
				
			||||||
                    expected: SyntaxKind::Declaration,
 | 
					                    expected: SyntaxKind::Declaration,
 | 
				
			||||||
                    found: unexpected.into_token(),
 | 
					                    found: unexpected.into_token(),
 | 
				
			||||||
                }));
 | 
					                });
 | 
				
			||||||
 | 
					                handler.receive(err.clone());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                None
 | 
					                Err(err)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn parse_function(&mut self, handler: &impl Handler<base::Error>) -> Option<Function> {
 | 
					    /// Parses a function.
 | 
				
			||||||
        if let Reading::Atomic(Token::Keyword(function_keyword)) = self.stop_at_significant() {
 | 
					    ///
 | 
				
			||||||
 | 
					    /// # Errors
 | 
				
			||||||
 | 
					    /// - if the parser is not at a function (not at annotation).
 | 
				
			||||||
 | 
					    /// - if the parsing of the function fails.
 | 
				
			||||||
 | 
					    pub fn parse_function(&mut self, handler: &impl Handler<base::Error>) -> ParseResult<Function> {
 | 
				
			||||||
 | 
					        let pub_keyword =
 | 
				
			||||||
 | 
					            self.try_parse(|parser| parser.parse_keyword(KeywordKind::Pub, &VoidHandler));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        match self.stop_at_significant() {
 | 
				
			||||||
 | 
					            Reading::Atomic(Token::Keyword(function_keyword))
 | 
				
			||||||
 | 
					                if function_keyword.keyword == KeywordKind::Function =>
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
                // eat the function keyword
 | 
					                // eat the function keyword
 | 
				
			||||||
                self.forward();
 | 
					                self.forward();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -419,8 +427,8 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
                // parse the block
 | 
					                // parse the block
 | 
				
			||||||
                let block = self.parse_block(handler)?;
 | 
					                let block = self.parse_block(handler)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Some(Function {
 | 
					                Ok(Function {
 | 
				
			||||||
                public_keyword: None,
 | 
					                    public_keyword: pub_keyword.ok(),
 | 
				
			||||||
                    annotations: Vec::new(),
 | 
					                    annotations: Vec::new(),
 | 
				
			||||||
                    function_keyword,
 | 
					                    function_keyword,
 | 
				
			||||||
                    identifier,
 | 
					                    identifier,
 | 
				
			||||||
| 
						 | 
					@ -429,12 +437,15 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
                    close_paren: delimited_tree.close,
 | 
					                    close_paren: delimited_tree.close,
 | 
				
			||||||
                    block,
 | 
					                    block,
 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
        } else {
 | 
					            }
 | 
				
			||||||
            handler.receive(Error::UnexpectedSyntax(UnexpectedSyntax {
 | 
					            unexpected => {
 | 
				
			||||||
 | 
					                let err = Error::UnexpectedSyntax(UnexpectedSyntax {
 | 
				
			||||||
                    expected: SyntaxKind::Keyword(KeywordKind::Function),
 | 
					                    expected: SyntaxKind::Keyword(KeywordKind::Function),
 | 
				
			||||||
                found: self.peek().into_token(),
 | 
					                    found: unexpected.into_token(),
 | 
				
			||||||
            }));
 | 
					                });
 | 
				
			||||||
            None
 | 
					                handler.receive(err.clone());
 | 
				
			||||||
 | 
					                Err(err)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,7 +14,8 @@ use crate::{
 | 
				
			||||||
        token_stream::Delimiter,
 | 
					        token_stream::Delimiter,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    syntax::{
 | 
					    syntax::{
 | 
				
			||||||
        error::{Error, UnexpectedSyntax},
 | 
					        self,
 | 
				
			||||||
 | 
					        error::{Error, ParseResult, UnexpectedSyntax},
 | 
				
			||||||
        parser::{Parser, Reading},
 | 
					        parser::{Parser, Reading},
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -156,12 +157,22 @@ impl LuaCode {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<'a> Parser<'a> {
 | 
					impl<'a> Parser<'a> {
 | 
				
			||||||
    /// Parses an [`Expression`]
 | 
					    /// Parses an [`Expression`]
 | 
				
			||||||
    pub fn parse_expression(&mut self, handler: &impl Handler<base::Error>) -> Option<Expression> {
 | 
					    ///
 | 
				
			||||||
        Some(Expression::Primary(self.parse_primary(handler)?))
 | 
					    /// # Errors
 | 
				
			||||||
 | 
					    /// - If the parser is not at a primary expression.
 | 
				
			||||||
 | 
					    pub fn parse_expression(
 | 
				
			||||||
 | 
					        &mut self,
 | 
				
			||||||
 | 
					        handler: &impl Handler<base::Error>,
 | 
				
			||||||
 | 
					    ) -> ParseResult<Expression> {
 | 
				
			||||||
 | 
					        self.parse_primary(handler).map(Expression::Primary)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Parses an [`Primary`]
 | 
					    /// Parses an [`Primary`]
 | 
				
			||||||
    pub fn parse_primary(&mut self, handler: &impl Handler<base::Error>) -> Option<Primary> {
 | 
					    ///
 | 
				
			||||||
 | 
					    /// # Errors
 | 
				
			||||||
 | 
					    /// - If the parser is not at a primary expression.
 | 
				
			||||||
 | 
					    /// - If the parser is not at a valid primary expression.
 | 
				
			||||||
 | 
					    pub fn parse_primary(&mut self, handler: &impl Handler<base::Error>) -> ParseResult<Primary> {
 | 
				
			||||||
        match self.stop_at_significant() {
 | 
					        match self.stop_at_significant() {
 | 
				
			||||||
            // identifier expression
 | 
					            // identifier expression
 | 
				
			||||||
            Reading::Atomic(Token::Identifier(identifier)) => {
 | 
					            Reading::Atomic(Token::Identifier(identifier)) => {
 | 
				
			||||||
| 
						 | 
					@ -169,8 +180,8 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
                self.forward();
 | 
					                self.forward();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // function call
 | 
					                // function call
 | 
				
			||||||
                if matches!(self.stop_at_significant(), Reading::IntoDelimited(punc) if punc.punctuation == '(')
 | 
					                match self.stop_at_significant() {
 | 
				
			||||||
                {
 | 
					                    Reading::IntoDelimited(punc) if punc.punctuation == '(' => {
 | 
				
			||||||
                        let token_tree = self.parse_enclosed_list(
 | 
					                        let token_tree = self.parse_enclosed_list(
 | 
				
			||||||
                            Delimiter::Parenthesis,
 | 
					                            Delimiter::Parenthesis,
 | 
				
			||||||
                            ',',
 | 
					                            ',',
 | 
				
			||||||
| 
						 | 
					@ -178,15 +189,22 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
                            handler,
 | 
					                            handler,
 | 
				
			||||||
                        )?;
 | 
					                        )?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    Some(Primary::FunctionCall(FunctionCall {
 | 
					                        Ok(Primary::FunctionCall(FunctionCall {
 | 
				
			||||||
                            identifier,
 | 
					                            identifier,
 | 
				
			||||||
                            left_parenthesis: token_tree.open,
 | 
					                            left_parenthesis: token_tree.open,
 | 
				
			||||||
                            right_parenthesis: token_tree.close,
 | 
					                            right_parenthesis: token_tree.close,
 | 
				
			||||||
                            arguments: token_tree.list,
 | 
					                            arguments: token_tree.list,
 | 
				
			||||||
                        }))
 | 
					                        }))
 | 
				
			||||||
                } else {
 | 
					                    }
 | 
				
			||||||
 | 
					                    unexpected => {
 | 
				
			||||||
                        // insert parser for regular identifier here
 | 
					                        // insert parser for regular identifier here
 | 
				
			||||||
                    None
 | 
					                        let err = Error::UnexpectedSyntax(UnexpectedSyntax {
 | 
				
			||||||
 | 
					                            expected: syntax::error::SyntaxKind::Punctuation('('),
 | 
				
			||||||
 | 
					                            found: unexpected.into_token(),
 | 
				
			||||||
 | 
					                        });
 | 
				
			||||||
 | 
					                        handler.receive(err.clone());
 | 
				
			||||||
 | 
					                        Err(err)
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -195,7 +213,7 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
                // eat the string literal
 | 
					                // eat the string literal
 | 
				
			||||||
                self.forward();
 | 
					                self.forward();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Some(Primary::StringLiteral(literal))
 | 
					                Ok(Primary::StringLiteral(literal))
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // lua code expression
 | 
					            // lua code expression
 | 
				
			||||||
| 
						 | 
					@ -212,9 +230,16 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
                    |parser| match parser.next_significant_token() {
 | 
					                    |parser| match parser.next_significant_token() {
 | 
				
			||||||
                        Reading::Atomic(Token::Identifier(identifier)) => {
 | 
					                        Reading::Atomic(Token::Identifier(identifier)) => {
 | 
				
			||||||
                            parser.forward();
 | 
					                            parser.forward();
 | 
				
			||||||
                            Some(identifier)
 | 
					                            Ok(identifier)
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                        unexpected => {
 | 
				
			||||||
 | 
					                            let err = Error::UnexpectedSyntax(UnexpectedSyntax {
 | 
				
			||||||
 | 
					                                expected: syntax::error::SyntaxKind::Identifier,
 | 
				
			||||||
 | 
					                                found: unexpected.into_token(),
 | 
				
			||||||
 | 
					                            });
 | 
				
			||||||
 | 
					                            handler.receive(err.clone());
 | 
				
			||||||
 | 
					                            Err(err)
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        _ => None,
 | 
					 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
                    handler,
 | 
					                    handler,
 | 
				
			||||||
                )?;
 | 
					                )?;
 | 
				
			||||||
| 
						 | 
					@ -241,12 +266,12 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
                            })
 | 
					                            })
 | 
				
			||||||
                            .expect("Invalid lua code span");
 | 
					                            .expect("Invalid lua code span");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        Some(combined.str().trim().to_owned())
 | 
					                        Ok(combined.str().trim().to_owned())
 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
                    handler,
 | 
					                    handler,
 | 
				
			||||||
                )?;
 | 
					                )?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Some(Primary::Lua(Box::new(LuaCode {
 | 
					                Ok(Primary::Lua(Box::new(LuaCode {
 | 
				
			||||||
                    lua_keyword,
 | 
					                    lua_keyword,
 | 
				
			||||||
                    left_parenthesis: variables.open,
 | 
					                    left_parenthesis: variables.open,
 | 
				
			||||||
                    variables: variables.list,
 | 
					                    variables: variables.list,
 | 
				
			||||||
| 
						 | 
					@ -261,12 +286,13 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
                // make progress
 | 
					                // make progress
 | 
				
			||||||
                self.forward();
 | 
					                self.forward();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                handler.receive(Error::UnexpectedSyntax(UnexpectedSyntax {
 | 
					                let err = Error::UnexpectedSyntax(UnexpectedSyntax {
 | 
				
			||||||
                    expected: crate::syntax::error::SyntaxKind::Expression,
 | 
					                    expected: syntax::error::SyntaxKind::Expression,
 | 
				
			||||||
                    found: unexpected.into_token(),
 | 
					                    found: unexpected.into_token(),
 | 
				
			||||||
                }));
 | 
					                });
 | 
				
			||||||
 | 
					                handler.receive(err.clone());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                None
 | 
					                Err(err)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,7 +15,7 @@ use crate::{
 | 
				
			||||||
    syntax::parser::Reading,
 | 
					    syntax::parser::Reading,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use super::parser::Parser;
 | 
					use super::{error::ParseResult, parser::Parser};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub mod condition;
 | 
					pub mod condition;
 | 
				
			||||||
pub mod declaration;
 | 
					pub mod declaration;
 | 
				
			||||||
| 
						 | 
					@ -76,9 +76,9 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        delimiter: Delimiter,
 | 
					        delimiter: Delimiter,
 | 
				
			||||||
        separator: char,
 | 
					        separator: char,
 | 
				
			||||||
        mut f: impl FnMut(&mut Self) -> Option<T>,
 | 
					        mut f: impl FnMut(&mut Self) -> ParseResult<T>,
 | 
				
			||||||
        handler: &impl Handler<base::Error>,
 | 
					        handler: &impl Handler<base::Error>,
 | 
				
			||||||
    ) -> Option<DelimitedList<T>> {
 | 
					    ) -> ParseResult<DelimitedList<T>> {
 | 
				
			||||||
        fn skip_to_next_separator(this: &mut Parser, separator: char) -> Option<Punctuation> {
 | 
					        fn skip_to_next_separator(this: &mut Parser, separator: char) -> Option<Punctuation> {
 | 
				
			||||||
            if let Reading::Atomic(Token::Punctuation(punc)) = this.stop_at(|token| {
 | 
					            if let Reading::Atomic(Token::Punctuation(punc)) = this.stop_at(|token| {
 | 
				
			||||||
                matches!(
 | 
					                matches!(
 | 
				
			||||||
| 
						 | 
					@ -101,7 +101,7 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
                let mut trailing_separator: Option<Punctuation> = None;
 | 
					                let mut trailing_separator: Option<Punctuation> = None;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                while !parser.is_exhausted() {
 | 
					                while !parser.is_exhausted() {
 | 
				
			||||||
                    let Some(element) = f(parser) else {
 | 
					                    let Ok(element) = f(parser) else {
 | 
				
			||||||
                        skip_to_next_separator(parser, separator);
 | 
					                        skip_to_next_separator(parser, separator);
 | 
				
			||||||
                        continue;
 | 
					                        continue;
 | 
				
			||||||
                    };
 | 
					                    };
 | 
				
			||||||
| 
						 | 
					@ -122,7 +122,7 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    // expect separator if not exhausted
 | 
					                    // expect separator if not exhausted
 | 
				
			||||||
                    if !parser.is_exhausted() {
 | 
					                    if !parser.is_exhausted() {
 | 
				
			||||||
                        let Some(separator) = parser.parse_punctuation(separator, true, handler)
 | 
					                        let Ok(separator) = parser.parse_punctuation(separator, true, handler)
 | 
				
			||||||
                        else {
 | 
					                        else {
 | 
				
			||||||
                            if let Some(punctuation) = skip_to_next_separator(parser, separator) {
 | 
					                            if let Some(punctuation) = skip_to_next_separator(parser, separator) {
 | 
				
			||||||
                                trailing_separator = Some(punctuation);
 | 
					                                trailing_separator = Some(punctuation);
 | 
				
			||||||
| 
						 | 
					@ -135,7 +135,7 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Some(first.map(|first| ConnectedList {
 | 
					                Ok(first.map(|first| ConnectedList {
 | 
				
			||||||
                    first,
 | 
					                    first,
 | 
				
			||||||
                    rest,
 | 
					                    rest,
 | 
				
			||||||
                    trailing_separator,
 | 
					                    trailing_separator,
 | 
				
			||||||
| 
						 | 
					@ -144,7 +144,7 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
            handler,
 | 
					            handler,
 | 
				
			||||||
        )?;
 | 
					        )?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Some(DelimitedList {
 | 
					        Ok(DelimitedList {
 | 
				
			||||||
            open: delimited_tree.open,
 | 
					            open: delimited_tree.open,
 | 
				
			||||||
            list: delimited_tree.tree.unwrap(),
 | 
					            list: delimited_tree.tree.unwrap(),
 | 
				
			||||||
            close: delimited_tree.close,
 | 
					            close: delimited_tree.close,
 | 
				
			||||||
| 
						 | 
					@ -162,20 +162,20 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
    pub fn parse_connected_list<T>(
 | 
					    pub fn parse_connected_list<T>(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        seperator: char,
 | 
					        seperator: char,
 | 
				
			||||||
        mut f: impl FnMut(&mut Self) -> Option<T>,
 | 
					        mut f: impl FnMut(&mut Self) -> ParseResult<T>,
 | 
				
			||||||
        _handler: &impl Handler<base::Error>,
 | 
					        _handler: &impl Handler<base::Error>,
 | 
				
			||||||
    ) -> Option<ConnectedList<T, Punctuation>> {
 | 
					    ) -> ParseResult<ConnectedList<T, Punctuation>> {
 | 
				
			||||||
        let first = f(self)?;
 | 
					        let first = f(self)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let mut rest = Vec::new();
 | 
					        let mut rest = Vec::new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        while let Some(sep) =
 | 
					        while let Ok(sep) =
 | 
				
			||||||
            self.try_parse(|parser| parser.parse_punctuation(seperator, true, &VoidHandler))
 | 
					            self.try_parse(|parser| parser.parse_punctuation(seperator, true, &VoidHandler))
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if let Some(element) = self.try_parse(&mut f) {
 | 
					            if let Ok(element) = self.try_parse(&mut f) {
 | 
				
			||||||
                rest.push((sep, element));
 | 
					                rest.push((sep, element));
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                return Some(ConnectedList {
 | 
					                return Ok(ConnectedList {
 | 
				
			||||||
                    first,
 | 
					                    first,
 | 
				
			||||||
                    rest,
 | 
					                    rest,
 | 
				
			||||||
                    trailing_separator: Some(sep),
 | 
					                    trailing_separator: Some(sep),
 | 
				
			||||||
| 
						 | 
					@ -183,7 +183,7 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Some(ConnectedList {
 | 
					        Ok(ConnectedList {
 | 
				
			||||||
            first,
 | 
					            first,
 | 
				
			||||||
            rest,
 | 
					            rest,
 | 
				
			||||||
            trailing_separator: None,
 | 
					            trailing_separator: None,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,7 @@
 | 
				
			||||||
//! The program node of the syntax tree.
 | 
					//! The program node of the syntax tree.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use getset::Getters;
 | 
					use getset::Getters;
 | 
				
			||||||
 | 
					use itertools::Itertools;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    base::{
 | 
					    base::{
 | 
				
			||||||
| 
						 | 
					@ -11,7 +12,7 @@ use crate::{
 | 
				
			||||||
    lexical::token::{Keyword, KeywordKind, Punctuation, StringLiteral, Token},
 | 
					    lexical::token::{Keyword, KeywordKind, Punctuation, StringLiteral, Token},
 | 
				
			||||||
    syntax::{
 | 
					    syntax::{
 | 
				
			||||||
        self,
 | 
					        self,
 | 
				
			||||||
        error::{SyntaxKind, UnexpectedSyntax},
 | 
					        error::{InvalidArgument, ParseResult, SyntaxKind, UnexpectedSyntax},
 | 
				
			||||||
        parser::{Parser, Reading},
 | 
					        parser::{Parser, Reading},
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -70,18 +71,34 @@ impl Namespace {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Validates a namespace string.
 | 
					    /// Validates a namespace string.
 | 
				
			||||||
    #[must_use]
 | 
					    ///
 | 
				
			||||||
    pub fn validate_str(namespace: &str) -> bool {
 | 
					    /// # Errors
 | 
				
			||||||
 | 
					    /// - If the namespace contains invalid characters.
 | 
				
			||||||
 | 
					    pub fn validate_str(namespace: &str) -> Result<(), String> {
 | 
				
			||||||
        const VALID_CHARS: &str = "0123456789abcdefghijklmnopqrstuvwxyz_-.";
 | 
					        const VALID_CHARS: &str = "0123456789abcdefghijklmnopqrstuvwxyz_-.";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        namespace.chars().all(|c| VALID_CHARS.contains(c))
 | 
					        let invalid_chars = namespace
 | 
				
			||||||
 | 
					            .chars()
 | 
				
			||||||
 | 
					            .filter(|c| !VALID_CHARS.contains(*c))
 | 
				
			||||||
 | 
					            .sorted()
 | 
				
			||||||
 | 
					            .unique()
 | 
				
			||||||
 | 
					            .collect::<String>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if invalid_chars.is_empty() {
 | 
				
			||||||
 | 
					            Ok(())
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            Err(invalid_chars)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<'a> Parser<'a> {
 | 
					impl<'a> Parser<'a> {
 | 
				
			||||||
    /// Parses a [`ProgramFile`].
 | 
					    /// Parses a [`ProgramFile`].
 | 
				
			||||||
    #[tracing::instrument(level = "debug", skip_all)]
 | 
					    #[tracing::instrument(level = "debug", skip_all)]
 | 
				
			||||||
    pub fn parse_program(&mut self, handler: &impl Handler<base::Error>) -> Option<ProgramFile> {
 | 
					    pub fn parse_program(
 | 
				
			||||||
 | 
					        &mut self,
 | 
				
			||||||
 | 
					        handler: &impl Handler<base::Error>,
 | 
				
			||||||
 | 
					    ) -> ParseResult<ProgramFile> {
 | 
				
			||||||
        tracing::debug!("Parsing program");
 | 
					        tracing::debug!("Parsing program");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let namespace = match self.stop_at_significant() {
 | 
					        let namespace = match self.stop_at_significant() {
 | 
				
			||||||
| 
						 | 
					@ -92,23 +109,37 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
                self.forward();
 | 
					                self.forward();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                let namespace_name = self.parse_string_literal(handler).and_then(|name| {
 | 
					                let namespace_name = self.parse_string_literal(handler).and_then(|name| {
 | 
				
			||||||
                    Namespace::validate_str(name.str_content().as_ref()).then_some(name)
 | 
					                    Namespace::validate_str(name.str_content().as_ref())
 | 
				
			||||||
 | 
					                        .map(|()| name.clone())
 | 
				
			||||||
 | 
					                        .map_err(|invalid| {
 | 
				
			||||||
 | 
					                            let err = syntax::error::Error::InvalidArgument(InvalidArgument {
 | 
				
			||||||
 | 
					                                message: format!(
 | 
				
			||||||
 | 
					                                    "Invalid characters in namespace '{}'. The following characters are not allowed in namespace definitions: '{}'",
 | 
				
			||||||
 | 
					                                    name.str_content(),
 | 
				
			||||||
 | 
					                                    invalid
 | 
				
			||||||
 | 
					                                ),
 | 
				
			||||||
 | 
					                                span: name.span(),
 | 
				
			||||||
 | 
					                            });
 | 
				
			||||||
 | 
					                            handler.receive(err.clone());
 | 
				
			||||||
 | 
					                            err
 | 
				
			||||||
 | 
					                        })
 | 
				
			||||||
                })?;
 | 
					                })?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                let semicolon = self.parse_punctuation(';', true, handler)?;
 | 
					                let semicolon = self.parse_punctuation(';', true, handler)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Some(Namespace {
 | 
					                Ok(Namespace {
 | 
				
			||||||
                    namespace_keyword,
 | 
					                    namespace_keyword,
 | 
				
			||||||
                    namespace_name,
 | 
					                    namespace_name,
 | 
				
			||||||
                    semicolon,
 | 
					                    semicolon,
 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            unexpected => {
 | 
					            unexpected => {
 | 
				
			||||||
                handler.receive(syntax::error::Error::from(UnexpectedSyntax {
 | 
					                let err = syntax::error::Error::from(UnexpectedSyntax {
 | 
				
			||||||
                    expected: SyntaxKind::Keyword(KeywordKind::Namespace),
 | 
					                    expected: SyntaxKind::Keyword(KeywordKind::Namespace),
 | 
				
			||||||
                    found: unexpected.into_token(),
 | 
					                    found: unexpected.into_token(),
 | 
				
			||||||
                }));
 | 
					                });
 | 
				
			||||||
                None
 | 
					                handler.receive(err.clone());
 | 
				
			||||||
 | 
					                Err(err)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }?;
 | 
					        }?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -123,7 +154,7 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
            let result = self.parse_declaration(handler);
 | 
					            let result = self.parse_declaration(handler);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            #[allow(clippy::option_if_let_else)]
 | 
					            #[allow(clippy::option_if_let_else)]
 | 
				
			||||||
            if let Some(x) = result {
 | 
					            if let Ok(x) = result {
 | 
				
			||||||
                declarations.push(x);
 | 
					                declarations.push(x);
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                self.stop_at(|reading| {
 | 
					                self.stop_at(|reading| {
 | 
				
			||||||
| 
						 | 
					@ -137,7 +168,7 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Some(ProgramFile {
 | 
					        Ok(ProgramFile {
 | 
				
			||||||
            namespace,
 | 
					            namespace,
 | 
				
			||||||
            declarations,
 | 
					            declarations,
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,7 +15,10 @@ use crate::{
 | 
				
			||||||
        token::{CommandLiteral, DocComment, Keyword, KeywordKind, Punctuation, Token},
 | 
					        token::{CommandLiteral, DocComment, Keyword, KeywordKind, Punctuation, Token},
 | 
				
			||||||
        token_stream::Delimiter,
 | 
					        token_stream::Delimiter,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    syntax::parser::{Parser, Reading},
 | 
					    syntax::{
 | 
				
			||||||
 | 
					        error::ParseResult,
 | 
				
			||||||
 | 
					        parser::{Parser, Reading},
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use self::execute_block::ExecuteBlock;
 | 
					use self::execute_block::ExecuteBlock;
 | 
				
			||||||
| 
						 | 
					@ -209,7 +212,10 @@ impl Semicolon {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<'a> Parser<'a> {
 | 
					impl<'a> Parser<'a> {
 | 
				
			||||||
    /// Parses a [`Block`].
 | 
					    /// Parses a [`Block`].
 | 
				
			||||||
    pub fn parse_block(&mut self, handler: &impl Handler<base::Error>) -> Option<Block> {
 | 
					    ///
 | 
				
			||||||
 | 
					    /// # Errors
 | 
				
			||||||
 | 
					    /// - if the parser is not at a block.
 | 
				
			||||||
 | 
					    pub fn parse_block(&mut self, handler: &impl Handler<base::Error>) -> ParseResult<Block> {
 | 
				
			||||||
        let token_tree = self.step_into(
 | 
					        let token_tree = self.step_into(
 | 
				
			||||||
            Delimiter::Brace,
 | 
					            Delimiter::Brace,
 | 
				
			||||||
            |parser| {
 | 
					            |parser| {
 | 
				
			||||||
| 
						 | 
					@ -217,7 +223,7 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                while !parser.is_exhausted() {
 | 
					                while !parser.is_exhausted() {
 | 
				
			||||||
                    parser.parse_statement(handler).map_or_else(
 | 
					                    parser.parse_statement(handler).map_or_else(
 | 
				
			||||||
                        || {
 | 
					                        |_| {
 | 
				
			||||||
                            // error recovery
 | 
					                            // error recovery
 | 
				
			||||||
                            parser.stop_at(|reading| matches!(
 | 
					                            parser.stop_at(|reading| matches!(
 | 
				
			||||||
                                reading,
 | 
					                                reading,
 | 
				
			||||||
| 
						 | 
					@ -234,12 +240,12 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
                    );
 | 
					                    );
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Some(statements)
 | 
					                Ok(statements)
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            handler,
 | 
					            handler,
 | 
				
			||||||
        )?;
 | 
					        )?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Some(Block {
 | 
					        Ok(Block {
 | 
				
			||||||
            open_brace: token_tree.open,
 | 
					            open_brace: token_tree.open,
 | 
				
			||||||
            statements: token_tree.tree?,
 | 
					            statements: token_tree.tree?,
 | 
				
			||||||
            close_brace: token_tree.close,
 | 
					            close_brace: token_tree.close,
 | 
				
			||||||
| 
						 | 
					@ -248,19 +254,22 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Parses a [`Statement`].
 | 
					    /// Parses a [`Statement`].
 | 
				
			||||||
    #[tracing::instrument(level = "trace", skip_all)]
 | 
					    #[tracing::instrument(level = "trace", skip_all)]
 | 
				
			||||||
    pub fn parse_statement(&mut self, handler: &impl Handler<base::Error>) -> Option<Statement> {
 | 
					    pub fn parse_statement(
 | 
				
			||||||
 | 
					        &mut self,
 | 
				
			||||||
 | 
					        handler: &impl Handler<base::Error>,
 | 
				
			||||||
 | 
					    ) -> ParseResult<Statement> {
 | 
				
			||||||
        match self.stop_at_significant() {
 | 
					        match self.stop_at_significant() {
 | 
				
			||||||
            // variable declaration
 | 
					            // variable declaration
 | 
				
			||||||
            Reading::Atomic(Token::CommandLiteral(command)) => {
 | 
					            Reading::Atomic(Token::CommandLiteral(command)) => {
 | 
				
			||||||
                self.forward();
 | 
					                self.forward();
 | 
				
			||||||
                tracing::trace!("Parsed literal command '{}'", command.clean_command());
 | 
					                tracing::trace!("Parsed literal command '{}'", command.clean_command());
 | 
				
			||||||
                Some(Statement::LiteralCommand(command))
 | 
					                Ok(Statement::LiteralCommand(command))
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            // block statement
 | 
					            // block statement
 | 
				
			||||||
            Reading::IntoDelimited(open_brace) if open_brace.punctuation == '{' => {
 | 
					            Reading::IntoDelimited(open_brace) if open_brace.punctuation == '{' => {
 | 
				
			||||||
                let block = self.parse_block(handler)?;
 | 
					                let block = self.parse_block(handler)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Some(Statement::Block(block))
 | 
					                Ok(Statement::Block(block))
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // execute block
 | 
					            // execute block
 | 
				
			||||||
| 
						 | 
					@ -274,7 +283,7 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
            // doc comment
 | 
					            // doc comment
 | 
				
			||||||
            Reading::Atomic(Token::DocComment(doc_comment)) => {
 | 
					            Reading::Atomic(Token::DocComment(doc_comment)) => {
 | 
				
			||||||
                self.forward();
 | 
					                self.forward();
 | 
				
			||||||
                Some(Statement::DocComment(doc_comment))
 | 
					                Ok(Statement::DocComment(doc_comment))
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // grouping statement
 | 
					            // grouping statement
 | 
				
			||||||
| 
						 | 
					@ -288,7 +297,7 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                tracing::trace!("Parsed group command");
 | 
					                tracing::trace!("Parsed group command");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Some(Statement::Grouping(Grouping {
 | 
					                Ok(Statement::Grouping(Grouping {
 | 
				
			||||||
                    group_keyword,
 | 
					                    group_keyword,
 | 
				
			||||||
                    block,
 | 
					                    block,
 | 
				
			||||||
                }))
 | 
					                }))
 | 
				
			||||||
| 
						 | 
					@ -306,7 +315,7 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                tracing::trace!("Parsed run statement: {:?}", expression);
 | 
					                tracing::trace!("Parsed run statement: {:?}", expression);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Some(Statement::Run(Run {
 | 
					                Ok(Statement::Run(Run {
 | 
				
			||||||
                    run_keyword,
 | 
					                    run_keyword,
 | 
				
			||||||
                    expression,
 | 
					                    expression,
 | 
				
			||||||
                    semicolon,
 | 
					                    semicolon,
 | 
				
			||||||
| 
						 | 
					@ -320,7 +329,7 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                tracing::trace!("Parsed semicolon statement: {:?}", expression);
 | 
					                tracing::trace!("Parsed semicolon statement: {:?}", expression);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Some(Statement::Semicolon(Semicolon {
 | 
					                Ok(Statement::Semicolon(Semicolon {
 | 
				
			||||||
                    expression,
 | 
					                    expression,
 | 
				
			||||||
                    semicolon,
 | 
					                    semicolon,
 | 
				
			||||||
                }))
 | 
					                }))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,15 +8,14 @@ use crate::{
 | 
				
			||||||
    base::{
 | 
					    base::{
 | 
				
			||||||
        self,
 | 
					        self,
 | 
				
			||||||
        source_file::{SourceElement, Span},
 | 
					        source_file::{SourceElement, Span},
 | 
				
			||||||
        VoidHandler, Handler,
 | 
					        Handler, VoidHandler,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    lexical::{
 | 
					    lexical::{
 | 
				
			||||||
        token::{Keyword, KeywordKind, Punctuation, StringLiteral, Token},
 | 
					        token::{Keyword, KeywordKind, Punctuation, StringLiteral, Token},
 | 
				
			||||||
        token_stream::Delimiter,
 | 
					        token_stream::Delimiter,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    syntax::{
 | 
					    syntax::{
 | 
				
			||||||
        self,
 | 
					        error::{Error, ParseResult, SyntaxKind, UnexpectedSyntax},
 | 
				
			||||||
        error::{SyntaxKind, UnexpectedSyntax},
 | 
					 | 
				
			||||||
        parser::{DelimitedTree, Parser, Reading},
 | 
					        parser::{DelimitedTree, Parser, Reading},
 | 
				
			||||||
        syntax_tree::condition::ParenthesizedCondition,
 | 
					        syntax_tree::condition::ParenthesizedCondition,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
| 
						 | 
					@ -711,10 +710,14 @@ impl Summon {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<'a> Parser<'a> {
 | 
					impl<'a> Parser<'a> {
 | 
				
			||||||
    /// Parses an [`ExecuteBlock`].
 | 
					    /// Parses an [`ExecuteBlock`].
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// # Errors
 | 
				
			||||||
 | 
					    /// - if not at the start of an execute block statement.
 | 
				
			||||||
 | 
					    /// - if the parsing of the execute block statement fails.
 | 
				
			||||||
    pub fn parse_execute_block_statement(
 | 
					    pub fn parse_execute_block_statement(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        handler: &impl Handler<base::Error>,
 | 
					        handler: &impl Handler<base::Error>,
 | 
				
			||||||
    ) -> Option<ExecuteBlock> {
 | 
					    ) -> ParseResult<ExecuteBlock> {
 | 
				
			||||||
        match self.stop_at_significant() {
 | 
					        match self.stop_at_significant() {
 | 
				
			||||||
            Reading::Atomic(Token::Keyword(if_keyword))
 | 
					            Reading::Atomic(Token::Keyword(if_keyword))
 | 
				
			||||||
                if if_keyword.keyword == KeywordKind::If =>
 | 
					                if if_keyword.keyword == KeywordKind::If =>
 | 
				
			||||||
| 
						 | 
					@ -739,14 +742,17 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
                            // eat the else keyword
 | 
					                            // eat the else keyword
 | 
				
			||||||
                            parser.forward();
 | 
					                            parser.forward();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            let else_block = parser.parse_block(handler)?;
 | 
					                            let else_block = parser.parse_block(&VoidHandler)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            Some((else_keyword, else_block))
 | 
					                            Ok((else_keyword, else_block))
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        _ => None,
 | 
					                        unexpected => Err(UnexpectedSyntax {
 | 
				
			||||||
 | 
					                            expected: SyntaxKind::Keyword(KeywordKind::Else),
 | 
				
			||||||
 | 
					                            found: unexpected.into_token(),
 | 
				
			||||||
 | 
					                        }),
 | 
				
			||||||
                    }?;
 | 
					                    }?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    Some((
 | 
					                    Ok((
 | 
				
			||||||
                        block,
 | 
					                        block,
 | 
				
			||||||
                        Else {
 | 
					                        Else {
 | 
				
			||||||
                            else_keyword,
 | 
					                            else_keyword,
 | 
				
			||||||
| 
						 | 
					@ -755,11 +761,11 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
                    ))
 | 
					                    ))
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if let Some((block, else_tail)) = else_tail {
 | 
					                if let Ok((block, else_tail)) = else_tail {
 | 
				
			||||||
                    Some(ExecuteBlock::IfElse(conditional, block, else_tail))
 | 
					                    Ok(ExecuteBlock::IfElse(conditional, block, else_tail))
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    let tail = self.parse_execute_block_tail(handler)?;
 | 
					                    let tail = self.parse_execute_block_tail(handler)?;
 | 
				
			||||||
                    Some(ExecuteBlock::HeadTail(
 | 
					                    Ok(ExecuteBlock::HeadTail(
 | 
				
			||||||
                        ExecuteBlockHead::Conditional(conditional),
 | 
					                        ExecuteBlockHead::Conditional(conditional),
 | 
				
			||||||
                        tail,
 | 
					                        tail,
 | 
				
			||||||
                    ))
 | 
					                    ))
 | 
				
			||||||
| 
						 | 
					@ -777,11 +783,12 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
                        handler,
 | 
					                        handler,
 | 
				
			||||||
                    ),
 | 
					                    ),
 | 
				
			||||||
                    unexpected => {
 | 
					                    unexpected => {
 | 
				
			||||||
                        handler.receive(syntax::error::Error::from(UnexpectedSyntax {
 | 
					                        let err = Error::UnexpectedSyntax(UnexpectedSyntax {
 | 
				
			||||||
                            expected: SyntaxKind::Punctuation('('),
 | 
					                            expected: SyntaxKind::Punctuation('('),
 | 
				
			||||||
                            found: unexpected.into_token(),
 | 
					                            found: unexpected.into_token(),
 | 
				
			||||||
                        }));
 | 
					                        });
 | 
				
			||||||
                        None
 | 
					                        handler.receive(err.clone());
 | 
				
			||||||
 | 
					                        Err(err)
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }?;
 | 
					                }?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -789,16 +796,17 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                let head = head_from_keyword(keyword, argument)?;
 | 
					                let head = head_from_keyword(keyword, argument)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Some(ExecuteBlock::HeadTail(head, tail))
 | 
					                Ok(ExecuteBlock::HeadTail(head, tail))
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // unexpected
 | 
					            // unexpected
 | 
				
			||||||
            unexpected => {
 | 
					            unexpected => {
 | 
				
			||||||
                handler.receive(syntax::error::Error::from(UnexpectedSyntax {
 | 
					                let err = Error::UnexpectedSyntax(UnexpectedSyntax {
 | 
				
			||||||
                    expected: SyntaxKind::ExecuteBlock,
 | 
					                    expected: SyntaxKind::ExecuteBlock,
 | 
				
			||||||
                    found: unexpected.into_token(),
 | 
					                    found: unexpected.into_token(),
 | 
				
			||||||
                }));
 | 
					                });
 | 
				
			||||||
                None
 | 
					                handler.receive(err.clone());
 | 
				
			||||||
 | 
					                Err(err)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -806,7 +814,7 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
    fn parse_execute_block_tail(
 | 
					    fn parse_execute_block_tail(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        handler: &impl Handler<base::Error>,
 | 
					        handler: &impl Handler<base::Error>,
 | 
				
			||||||
    ) -> Option<ExecuteBlockTail> {
 | 
					    ) -> ParseResult<ExecuteBlockTail> {
 | 
				
			||||||
        match self.stop_at_significant() {
 | 
					        match self.stop_at_significant() {
 | 
				
			||||||
            // nested execute block
 | 
					            // nested execute block
 | 
				
			||||||
            Reading::Atomic(Token::Punctuation(punc)) if punc.punctuation == ',' => {
 | 
					            Reading::Atomic(Token::Punctuation(punc)) if punc.punctuation == ',' => {
 | 
				
			||||||
| 
						 | 
					@ -815,7 +823,7 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                let execute_block = self.parse_execute_block_statement(handler)?;
 | 
					                let execute_block = self.parse_execute_block_statement(handler)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Some(ExecuteBlockTail::ExecuteBlock(
 | 
					                Ok(ExecuteBlockTail::ExecuteBlock(
 | 
				
			||||||
                    punc,
 | 
					                    punc,
 | 
				
			||||||
                    Box::new(execute_block),
 | 
					                    Box::new(execute_block),
 | 
				
			||||||
                ))
 | 
					                ))
 | 
				
			||||||
| 
						 | 
					@ -825,15 +833,16 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
            Reading::IntoDelimited(punc) if punc.punctuation == '{' => {
 | 
					            Reading::IntoDelimited(punc) if punc.punctuation == '{' => {
 | 
				
			||||||
                let block = self.parse_block(handler)?;
 | 
					                let block = self.parse_block(handler)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Some(ExecuteBlockTail::Block(block))
 | 
					                Ok(ExecuteBlockTail::Block(block))
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            unexpected => {
 | 
					            unexpected => {
 | 
				
			||||||
                handler.receive(syntax::error::Error::from(UnexpectedSyntax {
 | 
					                let err = Error::UnexpectedSyntax(UnexpectedSyntax {
 | 
				
			||||||
                    expected: SyntaxKind::ExecuteBlockTail,
 | 
					                    expected: SyntaxKind::ExecuteBlockTail,
 | 
				
			||||||
                    found: unexpected.into_token(),
 | 
					                    found: unexpected.into_token(),
 | 
				
			||||||
                }));
 | 
					                });
 | 
				
			||||||
                None
 | 
					                handler.receive(err.clone());
 | 
				
			||||||
 | 
					                Err(err)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -842,8 +851,8 @@ impl<'a> Parser<'a> {
 | 
				
			||||||
fn head_from_keyword(
 | 
					fn head_from_keyword(
 | 
				
			||||||
    keyword: Keyword,
 | 
					    keyword: Keyword,
 | 
				
			||||||
    argument: DelimitedTree<StringLiteral>,
 | 
					    argument: DelimitedTree<StringLiteral>,
 | 
				
			||||||
) -> Option<ExecuteBlockHead> {
 | 
					) -> ParseResult<ExecuteBlockHead> {
 | 
				
			||||||
    Some(match keyword.keyword {
 | 
					    Ok(match keyword.keyword {
 | 
				
			||||||
        KeywordKind::Align => Align {
 | 
					        KeywordKind::Align => Align {
 | 
				
			||||||
            align_keyword: keyword,
 | 
					            align_keyword: keyword,
 | 
				
			||||||
            open_paren: argument.open,
 | 
					            open_paren: argument.open,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue