use std::mem::take;
use crate::language::ast::*;
pub fn exclude_statements<E>(statements: &mut AstTopLevel,
evaluate: &mut impl FnMut(AstExpression) -> Result<bool, E>)
-> Result<(), E>
{
let mut included = Vec::new();
for mut statement in take(statements)
{
match &mut statement
{
AstStatement::FunctionDefinition(function) =>
{
if let Some(mut condition) = function.condition.take()
{
exclude_expression(&mut condition, evaluate)?;
if !evaluate(condition)? { continue; }
}
exclude_statements(&mut function.body, evaluate)?;
},
AstStatement::BlockStatement(block) =>
{
if let Some(mut condition) = block.condition.take()
{
exclude_expression(&mut condition, evaluate)?;
if !evaluate(condition)? { continue; }
exclude_statements(&mut block.body, evaluate)?;
included.append(&mut block.body);
continue;
}
exclude_statements(&mut block.body, evaluate)?;
},
AstStatement::LoopStatement(block) => exclude_statements(&mut block.body, evaluate)?,
AstStatement::ForStatement(item) =>
{
exclude_expression(&mut item.iterable, evaluate)?;
exclude_statements(&mut item.body.body, evaluate)?;
},
AstStatement::ConditionalLoopStatement(item) =>
{
exclude_expression(&mut item.condition, evaluate)?;
exclude_statements(&mut item.body.body, evaluate)?;
},
AstStatement::LetStatement(item) => exclude_expression(&mut item.expression, evaluate)?,
AstStatement::SetStatement(item) =>
{
for access in &mut item.indexes
{
if let AstAccess::Index(index) = access
{ exclude_expression(index, evaluate)?; }
}
exclude_expression(&mut item.expression, evaluate)?;
},
AstStatement::ExpressionStatement(expression)
| AstStatement::DiscardStatement(expression) =>
exclude_expression(expression, evaluate)?,
AstStatement::ExecuteStatement(call) => exclude_call(call, evaluate)?,
AstStatement::ReturnStatement(item) =>
{
if let Some(expression) = &mut item.expression
{ exclude_expression(expression, evaluate)?; }
},
AstStatement::ImportStatement(item) =>
{
if let Some(expression) = &mut item.condition
{ exclude_expression(expression, evaluate)?; }
},
AstStatement::EnumDeclaration(_) | AstStatement::StructDeclaration(_)
| AstStatement::TypeDeclaration(_)
| AstStatement::AliasStatement(_) | AstStatement::BreakStatement(_)
| AstStatement::ContinueStatement(_) | AstStatement::NullStatement => {},
}
included.push(statement);
}
*statements = included;
Ok(())
}
fn exclude_call<E>(call: &mut AstExecuteStatement,
evaluate: &mut impl FnMut(AstExpression) -> Result<bool, E>) -> Result<(), E>
{
exclude_expression(&mut call.executable, evaluate)?;
for argument in &mut call.arguments { exclude_expression(argument, evaluate)?; }
Ok(())
}
fn exclude_expression<E>(expression: &mut AstExpression,
evaluate: &mut impl FnMut(AstExpression) -> Result<bool, E>)
-> Result<(), E>
{
match &mut expression.kind
{
AstExpressionKind::AnonymousFunction(function) =>
exclude_statements(&mut function.body, evaluate)?,
AstExpressionKind::IfExpression(item) =>
{
for branch in &mut item.branches
{
exclude_expression(&mut branch.condition, evaluate)?;
exclude_statements(&mut branch.body.body, evaluate)?;
}
if let Some(block) = &mut item.else_body
{ exclude_statements(&mut block.body, evaluate)?; }
},
AstExpressionKind::MatchExpression(item) =>
{
exclude_expression(&mut item.value, evaluate)?;
for arm in &mut item.arms
{
if let Some(pattern) = &mut arm.pattern
{ exclude_expression(pattern, evaluate)?; }
exclude_statements(&mut arm.body.body, evaluate)?;
}
},
AstExpressionKind::Execute(call) => exclude_call(call, evaluate)?,
AstExpressionKind::Array(values) =>
{ for value in values { exclude_expression(value, evaluate)?; } },
AstExpressionKind::HashMap(entries) =>
{
for (key, value) in entries
{
exclude_expression(key, evaluate)?;
exclude_expression(value, evaluate)?;
}
},
AstExpressionKind::StructConstructor(item) =>
{ for (_, _, value) in &mut item.fields { exclude_expression(value, evaluate)?; } },
AstExpressionKind::Range(start, end, _) =>
{
for bound in [start, end].into_iter().flatten()
{ exclude_expression(bound, evaluate)?; }
},
AstExpressionKind::Index(left, right) | AstExpressionKind::MathExpression(_, left, right)
| AstExpressionKind::BooleanExpression(_, left, right) =>
{
exclude_expression(left, evaluate)?;
exclude_expression(right, evaluate)?;
},
AstExpressionKind::Field(value, _, _) | AstExpressionKind::Splat(value)
| AstExpressionKind::Grouped(value) | AstExpressionKind::ExecutableReference(value)
| AstExpressionKind::TryExecute(value) | AstExpressionKind::MathNegate(value)
| AstExpressionKind::BooleanNot(value)
| AstExpressionKind::TypeConversion(_, value, _) =>
exclude_expression(value, evaluate)?,
AstExpressionKind::Redirect(value, redirects) =>
{
exclude_expression(value, evaluate)?;
for redirect in redirects { exclude_expression(&mut redirect.target, evaluate)?; }
},
AstExpressionKind::SpacedEmptyCall(_) | AstExpressionKind::EnumVariant(_, _)
| AstExpressionKind::Variable(_) | AstExpressionKind::VariableSplat(_)
| AstExpressionKind::Symbol(_) | AstExpressionKind::Literal(_) => {},
}
Ok(())
}