mirror of
https://github.com/nushell/nushell.git
synced 2025-05-29 14:21:45 +02:00
use unreachable! in run
This commit is contained in:
parent
dbc8da1f17
commit
debc913eeb
@ -34,10 +34,12 @@ impl Command for Break {
|
|||||||
&self,
|
&self,
|
||||||
_engine_state: &EngineState,
|
_engine_state: &EngineState,
|
||||||
_stack: &mut Stack,
|
_stack: &mut Stack,
|
||||||
call: &Call,
|
_call: &Call,
|
||||||
_input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
Err(ShellError::Break { span: call.head })
|
// This is compiled specially by the IR compiler. The code here is never used when
|
||||||
|
// running in IR mode.
|
||||||
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
@ -41,35 +41,14 @@ impl Command for Const {
|
|||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
_engine_state: &EngineState,
|
||||||
stack: &mut Stack,
|
_stack: &mut Stack,
|
||||||
call: &Call,
|
_call: &Call,
|
||||||
_input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
// This is compiled specially by the IR compiler. The code here is never used when
|
// This is compiled specially by the IR compiler. The code here is never used when
|
||||||
// running in IR mode.
|
// running in IR mode.
|
||||||
let call = call.assert_ast_call()?;
|
unreachable!()
|
||||||
let var_id = if let Some(id) = call.positional_nth(0).and_then(|pos| pos.as_var()) {
|
|
||||||
id
|
|
||||||
} else {
|
|
||||||
return Err(ShellError::NushellFailedSpanned {
|
|
||||||
msg: "Could not get variable".to_string(),
|
|
||||||
label: "variable not added by the parser".to_string(),
|
|
||||||
span: call.head,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(constval) = &engine_state.get_var(var_id).const_val {
|
|
||||||
stack.add_var(var_id, constval.clone());
|
|
||||||
|
|
||||||
Ok(PipelineData::empty())
|
|
||||||
} else {
|
|
||||||
Err(ShellError::NushellFailedSpanned {
|
|
||||||
msg: "Missing Constant".to_string(),
|
|
||||||
label: "constant not added by the parser".to_string(),
|
|
||||||
span: call.head,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_const(
|
fn run_const(
|
||||||
|
@ -33,10 +33,12 @@ impl Command for Continue {
|
|||||||
&self,
|
&self,
|
||||||
_engine_state: &EngineState,
|
_engine_state: &EngineState,
|
||||||
_stack: &mut Stack,
|
_stack: &mut Stack,
|
||||||
call: &Call,
|
_call: &Call,
|
||||||
_input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
Err(ShellError::Continue { span: call.head })
|
// This is compiled specially by the IR compiler. The code here is never used when
|
||||||
|
// running in IR mode.
|
||||||
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use nu_engine::{command_prelude::*, get_eval_block, get_eval_expression};
|
use nu_engine::command_prelude::*;
|
||||||
use nu_protocol::{engine::CommandType, Signals};
|
use nu_protocol::engine::CommandType;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct For;
|
pub struct For;
|
||||||
@ -43,83 +43,14 @@ impl Command for For {
|
|||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
_engine_state: &EngineState,
|
||||||
stack: &mut Stack,
|
_stack: &mut Stack,
|
||||||
call: &Call,
|
_call: &Call,
|
||||||
_input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
// This is compiled specially by the IR compiler. The code here is never used when
|
// This is compiled specially by the IR compiler. The code here is never used when
|
||||||
// running in IR mode.
|
// running in IR mode.
|
||||||
let call = call.assert_ast_call()?;
|
unreachable!()
|
||||||
let head = call.head;
|
|
||||||
let var_id = call
|
|
||||||
.positional_nth(0)
|
|
||||||
.expect("checked through parser")
|
|
||||||
.as_var()
|
|
||||||
.expect("internal error: missing variable");
|
|
||||||
|
|
||||||
let keyword_expr = call
|
|
||||||
.positional_nth(1)
|
|
||||||
.expect("checked through parser")
|
|
||||||
.as_keyword()
|
|
||||||
.expect("internal error: missing keyword");
|
|
||||||
|
|
||||||
let block_id = call
|
|
||||||
.positional_nth(2)
|
|
||||||
.expect("checked through parser")
|
|
||||||
.as_block()
|
|
||||||
.expect("internal error: missing block");
|
|
||||||
|
|
||||||
let eval_expression = get_eval_expression(engine_state);
|
|
||||||
let eval_block = get_eval_block(engine_state);
|
|
||||||
|
|
||||||
let value = eval_expression(engine_state, stack, keyword_expr)?;
|
|
||||||
|
|
||||||
let engine_state = engine_state.clone();
|
|
||||||
let block = engine_state.get_block(block_id);
|
|
||||||
|
|
||||||
let stack = &mut stack.push_redirection(None, None);
|
|
||||||
|
|
||||||
let span = value.span();
|
|
||||||
match value {
|
|
||||||
Value::List { vals, .. } => {
|
|
||||||
for x in vals.into_iter() {
|
|
||||||
engine_state.signals().check(head)?;
|
|
||||||
|
|
||||||
// with_env() is used here to ensure that each iteration uses
|
|
||||||
// a different set of environment variables.
|
|
||||||
// Hence, a 'cd' in the first loop won't affect the next loop.
|
|
||||||
|
|
||||||
stack.add_var(var_id, x);
|
|
||||||
|
|
||||||
match eval_block(&engine_state, stack, block, PipelineData::empty()) {
|
|
||||||
Err(ShellError::Break { .. }) => break,
|
|
||||||
Err(ShellError::Continue { .. }) => continue,
|
|
||||||
Err(err) => return Err(err),
|
|
||||||
Ok(data) => data.drain()?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Value::Range { val, .. } => {
|
|
||||||
for x in val.into_range_iter(span, Signals::empty()) {
|
|
||||||
engine_state.signals().check(head)?;
|
|
||||||
stack.add_var(var_id, x);
|
|
||||||
|
|
||||||
match eval_block(&engine_state, stack, block, PipelineData::empty()) {
|
|
||||||
Err(ShellError::Break { .. }) => break,
|
|
||||||
Err(ShellError::Continue { .. }) => continue,
|
|
||||||
Err(err) => return Err(err),
|
|
||||||
Ok(data) => data.drain()?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
x => {
|
|
||||||
stack.add_var(var_id, x);
|
|
||||||
|
|
||||||
eval_block(&engine_state, stack, block, PipelineData::empty())?.into_value(head)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(PipelineData::empty())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
use nu_engine::{
|
use nu_engine::command_prelude::*;
|
||||||
command_prelude::*, get_eval_block, get_eval_expression, get_eval_expression_with_input,
|
|
||||||
};
|
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
engine::{CommandType, StateWorkingSet},
|
engine::{CommandType, StateWorkingSet},
|
||||||
eval_const::{eval_const_subexpression, eval_constant, eval_constant_with_input},
|
eval_const::{eval_const_subexpression, eval_constant, eval_constant_with_input},
|
||||||
@ -60,8 +58,6 @@ impl Command for If {
|
|||||||
call: &Call,
|
call: &Call,
|
||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
// This is compiled specially by the IR compiler. The code here is never used when
|
|
||||||
// running in IR mode.
|
|
||||||
let call = call.assert_ast_call()?;
|
let call = call.assert_ast_call()?;
|
||||||
let cond = call.positional_nth(0).expect("checked through parser");
|
let cond = call.positional_nth(0).expect("checked through parser");
|
||||||
let then_block = call
|
let then_block = call
|
||||||
@ -97,43 +93,14 @@ impl Command for If {
|
|||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
_engine_state: &EngineState,
|
||||||
stack: &mut Stack,
|
_stack: &mut Stack,
|
||||||
call: &Call,
|
_call: &Call,
|
||||||
input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
// This is compiled specially by the IR compiler. The code here is never used when
|
// This is compiled specially by the IR compiler. The code here is never used when
|
||||||
// running in IR mode.
|
// running in IR mode.
|
||||||
let call = call.assert_ast_call()?;
|
unreachable!()
|
||||||
let cond = call.positional_nth(0).expect("checked through parser");
|
|
||||||
let then_block = call
|
|
||||||
.positional_nth(1)
|
|
||||||
.expect("checked through parser")
|
|
||||||
.as_block()
|
|
||||||
.expect("internal error: missing block");
|
|
||||||
let else_case = call.positional_nth(2);
|
|
||||||
|
|
||||||
let eval_expression = get_eval_expression(engine_state);
|
|
||||||
let eval_expression_with_input = get_eval_expression_with_input(engine_state);
|
|
||||||
let eval_block = get_eval_block(engine_state);
|
|
||||||
|
|
||||||
if eval_expression(engine_state, stack, cond)?.as_bool()? {
|
|
||||||
let block = engine_state.get_block(then_block);
|
|
||||||
eval_block(engine_state, stack, block, input)
|
|
||||||
} else if let Some(else_case) = else_case {
|
|
||||||
if let Some(else_expr) = else_case.as_keyword() {
|
|
||||||
if let Some(block_id) = else_expr.as_block() {
|
|
||||||
let block = engine_state.get_block(block_id);
|
|
||||||
eval_block(engine_state, stack, block, input)
|
|
||||||
} else {
|
|
||||||
eval_expression_with_input(engine_state, stack, else_expr, input)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
eval_expression_with_input(engine_state, stack, else_case, input)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Ok(PipelineData::empty())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn search_terms(&self) -> Vec<&str> {
|
fn search_terms(&self) -> Vec<&str> {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use nu_engine::{command_prelude::*, get_eval_block};
|
use nu_engine::command_prelude::*;
|
||||||
use nu_protocol::engine::CommandType;
|
use nu_protocol::engine::CommandType;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -41,47 +41,14 @@ impl Command for Let {
|
|||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
_engine_state: &EngineState,
|
||||||
stack: &mut Stack,
|
_stack: &mut Stack,
|
||||||
call: &Call,
|
_call: &Call,
|
||||||
input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
// This is compiled specially by the IR compiler. The code here is never used when
|
// This is compiled specially by the IR compiler. The code here is never used when
|
||||||
// running in IR mode.
|
// running in IR mode.
|
||||||
let call = call.assert_ast_call()?;
|
unreachable!()
|
||||||
let var_id = call
|
|
||||||
.positional_nth(0)
|
|
||||||
.expect("checked through parser")
|
|
||||||
.as_var()
|
|
||||||
.expect("internal error: missing variable");
|
|
||||||
|
|
||||||
let block_id = call
|
|
||||||
.positional_nth(1)
|
|
||||||
.expect("checked through parser")
|
|
||||||
.as_block()
|
|
||||||
.expect("internal error: missing right hand side");
|
|
||||||
|
|
||||||
let block = engine_state.get_block(block_id);
|
|
||||||
let eval_block = get_eval_block(engine_state);
|
|
||||||
let stack = &mut stack.start_collect_value();
|
|
||||||
let pipeline_data = eval_block(engine_state, stack, block, input)?;
|
|
||||||
let value = pipeline_data.into_value(call.head)?;
|
|
||||||
|
|
||||||
// if given variable type is Glob, and our result is string
|
|
||||||
// then nushell need to convert from Value::String to Value::Glob
|
|
||||||
// it's assigned by demand, then it's not quoted, and it's required to expand
|
|
||||||
// if we pass it to other commands.
|
|
||||||
let var_type = &engine_state.get_var(var_id).ty;
|
|
||||||
let val_span = value.span();
|
|
||||||
let value = match value {
|
|
||||||
Value::String { val, .. } if var_type == &Type::Glob => {
|
|
||||||
Value::glob(val, false, val_span)
|
|
||||||
}
|
|
||||||
value => value,
|
|
||||||
};
|
|
||||||
|
|
||||||
stack.add_var(var_id, value);
|
|
||||||
Ok(PipelineData::empty())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use nu_engine::{command_prelude::*, get_eval_block};
|
use nu_engine::command_prelude::*;
|
||||||
use nu_protocol::engine::CommandType;
|
use nu_protocol::engine::CommandType;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -32,37 +32,14 @@ impl Command for Loop {
|
|||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
_engine_state: &EngineState,
|
||||||
stack: &mut Stack,
|
_stack: &mut Stack,
|
||||||
call: &Call,
|
_call: &Call,
|
||||||
_input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
// This is compiled specially by the IR compiler. The code here is never used when
|
// This is compiled specially by the IR compiler. The code here is never used when
|
||||||
// running in IR mode.
|
// running in IR mode.
|
||||||
let call = call.assert_ast_call()?;
|
unreachable!()
|
||||||
let head = call.head;
|
|
||||||
let block_id = call
|
|
||||||
.positional_nth(0)
|
|
||||||
.expect("checked through parser")
|
|
||||||
.as_block()
|
|
||||||
.expect("internal error: missing block");
|
|
||||||
|
|
||||||
let block = engine_state.get_block(block_id);
|
|
||||||
let eval_block = get_eval_block(engine_state);
|
|
||||||
|
|
||||||
let stack = &mut stack.push_redirection(None, None);
|
|
||||||
|
|
||||||
loop {
|
|
||||||
engine_state.signals().check(head)?;
|
|
||||||
|
|
||||||
match eval_block(engine_state, stack, block, PipelineData::empty()) {
|
|
||||||
Err(ShellError::Break { .. }) => break,
|
|
||||||
Err(ShellError::Continue { .. }) => continue,
|
|
||||||
Err(err) => return Err(err),
|
|
||||||
Ok(data) => data.drain()?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(PipelineData::empty())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
use nu_engine::{
|
use nu_engine::command_prelude::*;
|
||||||
command_prelude::*, get_eval_block, get_eval_expression, get_eval_expression_with_input,
|
use nu_protocol::engine::CommandType;
|
||||||
};
|
|
||||||
use nu_protocol::engine::{CommandType, Matcher};
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Match;
|
pub struct Match;
|
||||||
@ -38,58 +36,14 @@ impl Command for Match {
|
|||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
_engine_state: &EngineState,
|
||||||
stack: &mut Stack,
|
_stack: &mut Stack,
|
||||||
call: &Call,
|
_call: &Call,
|
||||||
input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
// This is compiled specially by the IR compiler. The code here is never used when
|
// This is compiled specially by the IR compiler. The code here is never used when
|
||||||
// running in IR mode.
|
// running in IR mode.
|
||||||
let call = call.assert_ast_call()?;
|
unreachable!()
|
||||||
let value: Value = call.req(engine_state, stack, 0)?;
|
|
||||||
let matches = call
|
|
||||||
.positional_nth(1)
|
|
||||||
.expect("checked through parser")
|
|
||||||
.as_match_block()
|
|
||||||
.expect("missing match block");
|
|
||||||
|
|
||||||
let eval_expression = get_eval_expression(engine_state);
|
|
||||||
let eval_expression_with_input = get_eval_expression_with_input(engine_state);
|
|
||||||
let eval_block = get_eval_block(engine_state);
|
|
||||||
|
|
||||||
let mut match_variables = vec![];
|
|
||||||
for (pattern, expr) in matches {
|
|
||||||
if pattern.match_value(&value, &mut match_variables) {
|
|
||||||
// This case does match, go ahead and return the evaluated expression
|
|
||||||
for (id, value) in match_variables.drain(..) {
|
|
||||||
stack.add_var(id, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
let guard_matches = if let Some(guard) = &pattern.guard {
|
|
||||||
let Value::Bool { val, .. } = eval_expression(engine_state, stack, guard)?
|
|
||||||
else {
|
|
||||||
return Err(ShellError::MatchGuardNotBool { span: guard.span });
|
|
||||||
};
|
|
||||||
|
|
||||||
val
|
|
||||||
} else {
|
|
||||||
true
|
|
||||||
};
|
|
||||||
|
|
||||||
if guard_matches {
|
|
||||||
return if let Some(block_id) = expr.as_block() {
|
|
||||||
let block = engine_state.get_block(block_id);
|
|
||||||
eval_block(engine_state, stack, block, input)
|
|
||||||
} else {
|
|
||||||
eval_expression_with_input(engine_state, stack, expr, input)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
match_variables.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(PipelineData::Empty)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use nu_engine::{command_prelude::*, get_eval_block};
|
use nu_engine::command_prelude::*;
|
||||||
use nu_protocol::engine::CommandType;
|
use nu_protocol::engine::CommandType;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -41,47 +41,14 @@ impl Command for Mut {
|
|||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
_engine_state: &EngineState,
|
||||||
stack: &mut Stack,
|
_stack: &mut Stack,
|
||||||
call: &Call,
|
_call: &Call,
|
||||||
input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
// This is compiled specially by the IR compiler. The code here is never used when
|
// This is compiled specially by the IR compiler. The code here is never used when
|
||||||
// running in IR mode.
|
// running in IR mode.
|
||||||
let call = call.assert_ast_call()?;
|
unreachable!()
|
||||||
let var_id = call
|
|
||||||
.positional_nth(0)
|
|
||||||
.expect("checked through parser")
|
|
||||||
.as_var()
|
|
||||||
.expect("internal error: missing variable");
|
|
||||||
|
|
||||||
let block_id = call
|
|
||||||
.positional_nth(1)
|
|
||||||
.expect("checked through parser")
|
|
||||||
.as_block()
|
|
||||||
.expect("internal error: missing right hand side");
|
|
||||||
|
|
||||||
let block = engine_state.get_block(block_id);
|
|
||||||
let eval_block = get_eval_block(engine_state);
|
|
||||||
let stack = &mut stack.start_collect_value();
|
|
||||||
let pipeline_data = eval_block(engine_state, stack, block, input)?;
|
|
||||||
let value = pipeline_data.into_value(call.head)?;
|
|
||||||
|
|
||||||
// if given variable type is Glob, and our result is string
|
|
||||||
// then nushell need to convert from Value::String to Value::Glob
|
|
||||||
// it's assigned by demand, then it's not quoted, and it's required to expand
|
|
||||||
// if we pass it to other commands.
|
|
||||||
let var_type = &engine_state.get_var(var_id).ty;
|
|
||||||
let val_span = value.span();
|
|
||||||
let value = match value {
|
|
||||||
Value::String { val, .. } if var_type == &Type::Glob => {
|
|
||||||
Value::glob(val, false, val_span)
|
|
||||||
}
|
|
||||||
value => value,
|
|
||||||
};
|
|
||||||
|
|
||||||
stack.add_var(var_id, value);
|
|
||||||
Ok(PipelineData::empty())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
@ -35,17 +35,14 @@ impl Command for Return {
|
|||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
_engine_state: &EngineState,
|
||||||
stack: &mut Stack,
|
_stack: &mut Stack,
|
||||||
call: &Call,
|
_call: &Call,
|
||||||
_input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let return_value: Option<Value> = call.opt(engine_state, stack, 0)?;
|
// This is compiled specially by the IR compiler. The code here is never used when
|
||||||
let value = return_value.unwrap_or(Value::nothing(call.head));
|
// running in IR mode.
|
||||||
Err(ShellError::Return {
|
unreachable!()
|
||||||
span: call.head,
|
|
||||||
value: Box::new(value),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use nu_engine::{command_prelude::*, get_eval_block, EvalBlockFn};
|
use nu_engine::command_prelude::*;
|
||||||
use nu_protocol::engine::{Closure, CommandType};
|
use nu_protocol::engine::CommandType;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Try;
|
pub struct Try;
|
||||||
@ -42,36 +42,14 @@ impl Command for Try {
|
|||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
_engine_state: &EngineState,
|
||||||
stack: &mut Stack,
|
_stack: &mut Stack,
|
||||||
call: &Call,
|
_call: &Call,
|
||||||
input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let head = call.head;
|
|
||||||
// This is compiled specially by the IR compiler. The code here is never used when
|
// This is compiled specially by the IR compiler. The code here is never used when
|
||||||
// running in IR mode.
|
// running in IR mode.
|
||||||
let call = call.assert_ast_call()?;
|
unreachable!();
|
||||||
let try_block = call
|
|
||||||
.positional_nth(0)
|
|
||||||
.expect("checked through parser")
|
|
||||||
.as_block()
|
|
||||||
.expect("internal error: missing block");
|
|
||||||
|
|
||||||
let catch_block: Option<Closure> = call.opt(engine_state, stack, 1)?;
|
|
||||||
|
|
||||||
let try_block = engine_state.get_block(try_block);
|
|
||||||
let eval_block = get_eval_block(engine_state);
|
|
||||||
|
|
||||||
let result = eval_block(engine_state, stack, try_block, input)
|
|
||||||
.and_then(|pipeline| pipeline.drain_to_out_dests(engine_state, stack));
|
|
||||||
|
|
||||||
match result {
|
|
||||||
Err(err) => run_catch(err, head, catch_block, engine_state, stack, eval_block),
|
|
||||||
Ok(PipelineData::Value(Value::Error { error, .. }, ..)) => {
|
|
||||||
run_catch(*error, head, catch_block, engine_state, stack, eval_block)
|
|
||||||
}
|
|
||||||
Ok(pipeline) => Ok(pipeline),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
@ -95,52 +73,6 @@ impl Command for Try {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_catch(
|
|
||||||
error: ShellError,
|
|
||||||
span: Span,
|
|
||||||
catch: Option<Closure>,
|
|
||||||
engine_state: &EngineState,
|
|
||||||
stack: &mut Stack,
|
|
||||||
eval_block: EvalBlockFn,
|
|
||||||
) -> Result<PipelineData, ShellError> {
|
|
||||||
let error = intercept_block_control(error)?;
|
|
||||||
|
|
||||||
if let Some(catch) = catch {
|
|
||||||
stack.set_last_error(&error);
|
|
||||||
let error = error.into_value(&StateWorkingSet::new(engine_state), span);
|
|
||||||
let block = engine_state.get_block(catch.block_id);
|
|
||||||
// Put the error value in the positional closure var
|
|
||||||
if let Some(var) = block.signature.get_positional(0) {
|
|
||||||
if let Some(var_id) = &var.var_id {
|
|
||||||
stack.add_var(*var_id, error.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
eval_block(
|
|
||||||
engine_state,
|
|
||||||
stack,
|
|
||||||
block,
|
|
||||||
// Make the error accessible with $in, too
|
|
||||||
error.into_pipeline_data(),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
Ok(PipelineData::empty())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The flow control commands `break`/`continue`/`return` emit their own [`ShellError`] variants
|
|
||||||
/// We need to ignore those in `try` and bubble them through
|
|
||||||
///
|
|
||||||
/// `Err` when flow control to bubble up with `?`
|
|
||||||
fn intercept_block_control(error: ShellError) -> Result<ShellError, ShellError> {
|
|
||||||
match error {
|
|
||||||
ShellError::Break { .. } => Err(error),
|
|
||||||
ShellError::Continue { .. } => Err(error),
|
|
||||||
ShellError::Return { .. } => Err(error),
|
|
||||||
_ => Ok(error),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use nu_engine::{command_prelude::*, get_eval_block, get_eval_expression};
|
use nu_engine::command_prelude::*;
|
||||||
use nu_protocol::engine::CommandType;
|
use nu_protocol::engine::CommandType;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -41,58 +41,14 @@ impl Command for While {
|
|||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&self,
|
&self,
|
||||||
engine_state: &EngineState,
|
_engine_state: &EngineState,
|
||||||
stack: &mut Stack,
|
_stack: &mut Stack,
|
||||||
call: &Call,
|
_call: &Call,
|
||||||
_input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
// This is compiled specially by the IR compiler. The code here is never used when
|
// This is compiled specially by the IR compiler. The code here is never used when
|
||||||
// running in IR mode.
|
// running in IR mode.
|
||||||
let call = call.assert_ast_call()?;
|
unreachable!()
|
||||||
let head = call.head;
|
|
||||||
let cond = call.positional_nth(0).expect("checked through parser");
|
|
||||||
let block_id = call
|
|
||||||
.positional_nth(1)
|
|
||||||
.expect("checked through parser")
|
|
||||||
.as_block()
|
|
||||||
.expect("internal error: missing block");
|
|
||||||
|
|
||||||
let eval_expression = get_eval_expression(engine_state);
|
|
||||||
let eval_block = get_eval_block(engine_state);
|
|
||||||
|
|
||||||
let stack = &mut stack.push_redirection(None, None);
|
|
||||||
|
|
||||||
loop {
|
|
||||||
engine_state.signals().check(head)?;
|
|
||||||
|
|
||||||
let result = eval_expression(engine_state, stack, cond)?;
|
|
||||||
|
|
||||||
match &result {
|
|
||||||
Value::Bool { val, .. } => {
|
|
||||||
if *val {
|
|
||||||
let block = engine_state.get_block(block_id);
|
|
||||||
|
|
||||||
match eval_block(engine_state, stack, block, PipelineData::empty()) {
|
|
||||||
Err(ShellError::Break { .. }) => break,
|
|
||||||
Err(ShellError::Continue { .. }) => continue,
|
|
||||||
Err(err) => return Err(err),
|
|
||||||
Ok(data) => data.drain()?,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
x => {
|
|
||||||
return Err(ShellError::CantConvert {
|
|
||||||
to_type: "bool".into(),
|
|
||||||
from_type: x.get_type().to_string(),
|
|
||||||
span: result.span(),
|
|
||||||
help: None,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(PipelineData::empty())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examples(&self) -> Vec<Example> {
|
fn examples(&self) -> Vec<Example> {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user