use std::process;
use std::io::{self, Write};
use std::mem;
use super::status::*;
use super::Shell;
use super::flags::*;
use super::flow_control::{ElseIf, Function, Statement, collect_loops, collect_if};
use parser::{ForExpression, StatementSplitter, check_statement};
use parser::peg::Pipeline;
use super::assignments::let_assignment;
use glob::glob;
pub enum Condition {
Continue,
Break,
NoOp
}
pub trait FlowLogic {
fn on_command(&mut self, command_string: &str);
fn execute_toplevel<I>(&mut self, iterator: &mut I, statement: Statement) -> Result<(), &'static str>
where I: Iterator<Item = Statement>;
fn execute_while(&mut self, expression: Pipeline, statements: Vec<Statement>);
fn execute_for(&mut self, variable: &str, values: &[String], statements: Vec<Statement>);
fn execute_if(&mut self, expression: Pipeline, success: Vec<Statement>,
else_if: Vec<ElseIf>, failure: Vec<Statement>) -> Condition;
fn execute_statements(&mut self, statements: Vec<Statement>) -> Condition;
}
impl<'a> FlowLogic for Shell<'a> {
fn on_command(&mut self, command_string: &str) {
let mut iterator = StatementSplitter::new(command_string).filter_map(check_statement);
if self.flow_control.level == 0 {
while let Some(statement) = iterator.next() {
if let Err(why) = self.execute_toplevel(&mut iterator, statement) {
let stderr = io::stderr();
let mut stderr = stderr.lock();
let _ = writeln!(stderr, "{}", why);
self.flow_control.level = 0;
self.flow_control.current_if_mode = 0;
return
}
}
} else {
match self.flow_control.current_statement {
Statement::While{ ref mut statements, .. }
| Statement::For { ref mut statements, .. }
| Statement::Function { ref mut statements, .. } =>
{
collect_loops(&mut iterator, statements, &mut self.flow_control.level);
},
Statement::If { ref mut success, ref mut else_if, ref mut failure, .. } => {
self.flow_control.current_if_mode = match collect_if(&mut iterator, success,
else_if, failure, &mut self.flow_control.level,
self.flow_control.current_if_mode) {
Ok(mode) => mode,
Err(why) => {
let stderr = io::stderr();
let mut stderr = stderr.lock();
let _ = writeln!(stderr, "{}", why);
4
}
};
}
_ => ()
}
if self.flow_control.current_if_mode == 4 {
self.flow_control.level = 0;
self.flow_control.current_if_mode = 0;
self.flow_control.current_statement = Statement::Default;
return
}
if self.flow_control.level == 0 {
let mut replacement = Statement::Default;
mem::swap(&mut self.flow_control.current_statement, &mut replacement);
match replacement {
Statement::Let { expression } => {
self.previous_status = let_assignment(expression, &mut self.variables, &self.directory_stack);
},
Statement::While { expression, statements } => {
self.execute_while(expression, statements);
},
Statement::For { variable, values, statements } => {
self.execute_for(&variable, &values, statements);
},
Statement::Function { name, args, statements, description } => {
self.functions.insert(name.clone(), Function {
name: name,
args: args,
statements: statements,
description: description,
});
},
Statement::If { expression, success, else_if, failure } => {
self.execute_if(expression, success, else_if, failure);
}
_ => ()
}
while let Some(statement) = iterator.next() {
if let Err(why) = self.execute_toplevel(&mut iterator, statement) {
let stderr = io::stderr();
let mut stderr = stderr.lock();
let _ = writeln!(stderr, "{}", why);
self.flow_control.level = 0;
self.flow_control.current_if_mode = 0;
return
}
}
}
}
}
fn execute_statements(&mut self, mut statements: Vec<Statement>) -> Condition {
let mut iterator = statements.drain(..);
while let Some(statement) = iterator.next() {
match statement {
Statement::Let { expression } => {
self.previous_status = let_assignment(expression, &mut self.variables, &self.directory_stack);
},
Statement::While { expression, mut statements } => {
self.flow_control.level += 1;
collect_loops(&mut iterator, &mut statements, &mut self.flow_control.level);
self.execute_while(expression, statements);
},
Statement::For { variable, values, mut statements } => {
self.flow_control.level += 1;
collect_loops(&mut iterator, &mut statements, &mut self.flow_control.level);
self.execute_for(&variable, &values, statements);
},
Statement::If { expression, mut success, mut else_if, mut failure } => {
self.flow_control.level += 1;
if let Err(why) = collect_if(&mut iterator, &mut success, &mut else_if,
&mut failure, &mut self.flow_control.level, 0)
{
let stderr = io::stderr();
let mut stderr = stderr.lock();
let _ = writeln!(stderr, "{}", why);
self.flow_control.level = 0;
self.flow_control.current_if_mode = 0;
return Condition::Break
}
match self.execute_if(expression, success, else_if, failure) {
Condition::Break => return Condition::Break,
Condition::Continue => return Condition::Continue,
Condition::NoOp => ()
}
},
Statement::Function { name, args, mut statements, description } => {
self.flow_control.level += 1;
collect_loops(&mut iterator, &mut statements, &mut self.flow_control.level);
self.functions.insert(name.clone(), Function {
description: description,
name: name,
args: args,
statements: statements
});
},
Statement::Pipeline(mut pipeline) => {
self.run_pipeline(&mut pipeline);
if self.flags & ERR_EXIT != 0 && self.previous_status != SUCCESS {
process::exit(self.previous_status);
}
},
Statement::Break => { return Condition::Break }
Statement::Continue => { return Condition::Continue }
_ => {}
}
}
Condition::NoOp
}
fn execute_while(&mut self, expression: Pipeline, statements: Vec<Statement>) {
while self.run_pipeline(&mut expression.clone()) == Some(SUCCESS) {
if let Condition::Break = self.execute_statements(statements.clone()) {
break
}
}
}
fn execute_for(&mut self, variable: &str, values: &[String], statements: Vec<Statement>) {
fn glob_expand(arg: &str) -> Vec<String> {
let mut expanded = Vec::new();
if arg.contains(|chr| chr == '?' || chr == '*' || chr == '[') {
if let Ok(glob) = glob(arg) {
for path in glob.filter_map(Result::ok) {
expanded.push(path.to_string_lossy().into_owned());
}
}
expanded
} else {
vec![arg.to_owned()]
}
}
let ignore_variable = variable == "_";
match ForExpression::new(values, &self.directory_stack, &self.variables) {
ForExpression::Multiple(ref values) if ignore_variable => {
for _ in values.iter().flat_map(|x| glob_expand(&x)) {
if let Condition::Break = self.execute_statements(statements.clone()) { break }
}
},
ForExpression::Multiple(values) => {
for value in values.iter().flat_map(|x| glob_expand(&x)) {
self.variables.set_var(variable, &value);
if let Condition::Break = self.execute_statements(statements.clone()) { break }
}
},
ForExpression::Normal(ref values) if ignore_variable => {
for _ in values.lines().flat_map(glob_expand) {
if let Condition::Break = self.execute_statements(statements.clone()) { break }
}
},
ForExpression::Normal(values) => {
for value in values.lines().flat_map(glob_expand) {
self.variables.set_var(variable, &value);
if let Condition::Break = self.execute_statements(statements.clone()) { break }
}
},
ForExpression::Range(start, end) if ignore_variable => {
for _ in start..end {
if let Condition::Break = self.execute_statements(statements.clone()) { break }
}
}
ForExpression::Range(start, end) => {
for value in (start..end).map(|x| x.to_string()) {
self.variables.set_var(variable, &value);
if let Condition::Break = self.execute_statements(statements.clone()) { break }
}
}
}
}
fn execute_if(&mut self, mut expression: Pipeline, success: Vec<Statement>,
else_if: Vec<ElseIf>, failure: Vec<Statement>) -> Condition
{
match self.run_pipeline(&mut expression) {
Some(SUCCESS) => self.execute_statements(success),
_ => {
for mut elseif in else_if {
if self.run_pipeline(&mut elseif.expression) == Some(SUCCESS) {
return self.execute_statements(elseif.success);
}
}
self.execute_statements(failure)
}
}
}
fn execute_toplevel<I>(&mut self, iterator: &mut I, statement: Statement) -> Result<(), &'static str>
where I: Iterator<Item = Statement>
{
match statement {
Statement::Let { expression } => {
self.previous_status = let_assignment(expression, &mut self.variables, &self.directory_stack);
},
Statement::While { expression, mut statements } => {
self.flow_control.level += 1;
collect_loops(iterator, &mut statements, &mut self.flow_control.level);
if self.flow_control.level == 0 {
self.execute_while(expression, statements);
} else {
self.flow_control.current_statement = Statement::While {
expression: expression,
statements: statements,
}
}
},
Statement::For { variable, values, mut statements } => {
self.flow_control.level += 1;
collect_loops(iterator, &mut statements, &mut self.flow_control.level);
if self.flow_control.level == 0 {
self.execute_for(&variable, &values, statements);
} else {
self.flow_control.current_statement = Statement::For {
variable: variable,
values: values,
statements: statements,
}
}
},
Statement::If { expression, mut success, mut else_if, mut failure } => {
self.flow_control.level += 1;
let mode = collect_if(iterator, &mut success, &mut else_if,
&mut failure, &mut self.flow_control.level, 0)?;
if self.flow_control.level == 0 {
self.execute_if(expression, success, else_if, failure);
} else {
self.flow_control.current_if_mode = mode;
self.flow_control.current_statement = Statement::If {
expression: expression,
success: success,
else_if: else_if,
failure: failure
};
}
},
Statement::Function { name, args, mut statements, description } => {
self.flow_control.level += 1;
collect_loops(iterator, &mut statements, &mut self.flow_control.level);
if self.flow_control.level == 0 {
self.functions.insert(name.clone(), Function {
description: description,
name: name,
args: args,
statements: statements
});
} else {
self.flow_control.current_statement = Statement::Function {
description: description,
name: name,
args: args,
statements: statements
}
}
},
Statement::Pipeline(mut pipeline) => {
self.run_pipeline(&mut pipeline);
if self.flags & ERR_EXIT != 0 && self.previous_status != SUCCESS {
process::exit(self.previous_status);
}
},
Statement::ElseIf{..} | Statement::Else => {
let stderr = io::stderr();
let mut stderr = stderr.lock();
let _ = writeln!(stderr, "ion: syntax error: not an if statement");
},
Statement::End => {
let stderr = io::stderr();
let mut stderr = stderr.lock();
let _ = writeln!(stderr, "ion: syntax error: no block to end");
},
_ => {}
}
Ok(())
}
}