pub mod execute_block;
use derive_more::From;
use getset::Getters;
use crate::{
base::{
self,
source_file::{SourceElement, Span},
Handler,
},
lexical::{
token::{CommandLiteral, DocComment, Keyword, KeywordKind, Punctuation, Token},
token_stream::Delimiter,
},
syntax::{
error::ParseResult,
parser::{Parser, Reading},
},
};
use self::execute_block::ExecuteBlock;
use super::expression::Expression;
#[allow(missing_docs)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, From)]
pub enum Statement {
Block(Block),
LiteralCommand(CommandLiteral),
ExecuteBlock(ExecuteBlock),
Grouping(Grouping),
DocComment(DocComment),
Semicolon(Semicolon),
Run(Run),
}
impl SourceElement for Statement {
fn span(&self) -> Span {
match self {
Self::Block(block) => block.span(),
Self::LiteralCommand(literal_command) => literal_command.span(),
Self::ExecuteBlock(execute_block) => execute_block.span(),
Self::Grouping(grouping) => grouping.span(),
Self::DocComment(doc_comment) => doc_comment.span(),
Self::Semicolon(semi) => semi.span(),
Self::Run(run) => run.span(),
}
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Getters)]
pub struct Block {
#[get = "pub"]
pub open_brace: Punctuation,
#[get = "pub"]
pub statements: Vec<Statement>,
#[get = "pub"]
pub close_brace: Punctuation,
}
impl Block {
#[must_use]
pub fn dissolve(self) -> (Punctuation, Vec<Statement>, Punctuation) {
(self.open_brace, self.statements, self.close_brace)
}
}
impl SourceElement for Block {
fn span(&self) -> Span {
self.open_brace
.span()
.join(&self.close_brace.span())
.unwrap()
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Getters)]
pub struct Run {
#[get = "pub"]
run_keyword: Keyword,
#[get = "pub"]
expression: Expression,
#[get = "pub"]
semicolon: Punctuation,
}
impl SourceElement for Run {
fn span(&self) -> Span {
self.run_keyword
.span()
.join(&self.semicolon.span())
.expect("The span of the run statement is invalid.")
}
}
impl Run {
#[must_use]
pub fn dissolve(self) -> (Keyword, Expression, Punctuation) {
(self.run_keyword, self.expression, self.semicolon)
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Getters)]
pub struct Grouping {
#[get = "pub"]
group_keyword: Keyword,
#[get = "pub"]
block: Block,
}
impl Grouping {
#[must_use]
pub fn dissolve(self) -> (Keyword, Block) {
(self.group_keyword, self.block)
}
}
impl SourceElement for Grouping {
fn span(&self) -> Span {
self.group_keyword
.span()
.join(&self.block.span())
.expect("The span of the grouping is invalid.")
}
}
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Getters)]
pub struct Semicolon {
#[get = "pub"]
expression: Expression,
#[get = "pub"]
semicolon: Punctuation,
}
impl SourceElement for Semicolon {
fn span(&self) -> Span {
self.expression
.span()
.join(&self.semicolon.span())
.expect("The span of the semicolon statement is invalid.")
}
}
impl Semicolon {
#[must_use]
pub fn dissolve(self) -> (Expression, Punctuation) {
(self.expression, self.semicolon)
}
}
impl<'a> Parser<'a> {
pub fn parse_block(&mut self, handler: &impl Handler<base::Error>) -> ParseResult<Block> {
let token_tree = self.step_into(
Delimiter::Brace,
|parser| {
let mut statements = Vec::new();
while !parser.is_exhausted() {
parser.parse_statement(handler).map_or_else(
|_| {
parser.stop_at(|reading| matches!(
reading,
Reading::Atomic(Token::Punctuation(punc)) if punc.punctuation == ';'
) || matches!(
reading,
Reading::IntoDelimited(punc) if punc.punctuation == '{'
));
parser.forward();
},
|statement| statements.push(statement),
);
}
Ok(statements)
},
handler,
)?;
Ok(Block {
open_brace: token_tree.open,
statements: token_tree.tree?,
close_brace: token_tree.close,
})
}
#[tracing::instrument(level = "trace", skip_all)]
pub fn parse_statement(
&mut self,
handler: &impl Handler<base::Error>,
) -> ParseResult<Statement> {
match self.stop_at_significant() {
Reading::Atomic(Token::CommandLiteral(command)) => {
self.forward();
tracing::trace!("Parsed literal command '{}'", command.clean_command());
Ok(Statement::LiteralCommand(command))
}
Reading::IntoDelimited(open_brace) if open_brace.punctuation == '{' => {
let block = self.parse_block(handler)?;
Ok(Statement::Block(block))
}
Reading::Atomic(Token::Keyword(execute_keyword))
if execute_keyword.keyword.starts_execute_block() =>
{
self.parse_execute_block_statement(handler)
.map(Statement::ExecuteBlock)
}
Reading::Atomic(Token::DocComment(doc_comment)) => {
self.forward();
Ok(Statement::DocComment(doc_comment))
}
Reading::Atomic(Token::Keyword(group_keyword))
if group_keyword.keyword == KeywordKind::Group =>
{
self.forward();
let block = self.parse_block(handler)?;
tracing::trace!("Parsed group command");
Ok(Statement::Grouping(Grouping {
group_keyword,
block,
}))
}
Reading::Atomic(Token::Keyword(run_keyword))
if run_keyword.keyword == KeywordKind::Run =>
{
self.forward();
let expression = self.parse_expression(handler)?;
let semicolon = self.parse_punctuation(';', true, handler)?;
tracing::trace!("Parsed run statement: {:?}", expression);
Ok(Statement::Run(Run {
run_keyword,
expression,
semicolon,
}))
}
_ => {
let expression = self.parse_expression(handler)?;
let semicolon = self.parse_punctuation(';', true, handler)?;
tracing::trace!("Parsed semicolon statement: {:?}", expression);
Ok(Statement::Semicolon(Semicolon {
expression,
semicolon,
}))
}
}
}
}