mirror of
https://github.com/nushell/nushell.git
synced 2024-11-25 18:03:51 +01:00
Revert "Pipeline operators: &&
and ||
" (#7452)
Reverts nushell/nushell#7448 Some surprising behavior in how we do this. For example: ``` 〉if (true || false) { print "yes!" } else { print "no!" } no! 〉if (true or false) { print "yes!" } else { print "no!" } yes! ``` This means for folks who are using the old `||`, they possibly get the wrong answer once they upgrade. I don't think we can ship with that as it will catch too many people by surprise and just make it easier to write buggy code.
This commit is contained in:
parent
b7a3e5989d
commit
0c656fd276
@ -127,6 +127,7 @@ impl NuCompleter {
|
|||||||
match pipeline_element {
|
match pipeline_element {
|
||||||
PipelineElement::Expression(_, expr)
|
PipelineElement::Expression(_, expr)
|
||||||
| PipelineElement::Redirection(_, _, expr)
|
| PipelineElement::Redirection(_, _, expr)
|
||||||
|
| PipelineElement::And(_, expr)
|
||||||
| PipelineElement::Or(_, expr) => {
|
| PipelineElement::Or(_, expr) => {
|
||||||
let flattened: Vec<_> = flatten_expression(&working_set, &expr);
|
let flattened: Vec<_> = flatten_expression(&working_set, &expr);
|
||||||
let span_offset: usize = alias_offset.iter().sum();
|
let span_offset: usize = alias_offset.iter().sum();
|
||||||
|
@ -232,6 +232,7 @@ fn find_matching_block_end_in_block(
|
|||||||
match e {
|
match e {
|
||||||
PipelineElement::Expression(_, e)
|
PipelineElement::Expression(_, e)
|
||||||
| PipelineElement::Redirection(_, _, e)
|
| PipelineElement::Redirection(_, _, e)
|
||||||
|
| PipelineElement::And(_, e)
|
||||||
| PipelineElement::Or(_, e) => {
|
| PipelineElement::Or(_, e) => {
|
||||||
if e.span.contains(global_cursor_offset) {
|
if e.span.contains(global_cursor_offset) {
|
||||||
if let Some(pos) = find_matching_block_end_in_expr(
|
if let Some(pos) = find_matching_block_end_in_expr(
|
||||||
|
@ -146,6 +146,7 @@ impl Command for FromNuon {
|
|||||||
match pipeline.elements.remove(0) {
|
match pipeline.elements.remove(0) {
|
||||||
PipelineElement::Expression(_, expression)
|
PipelineElement::Expression(_, expression)
|
||||||
| PipelineElement::Redirection(_, _, expression)
|
| PipelineElement::Redirection(_, _, expression)
|
||||||
|
| PipelineElement::And(_, expression)
|
||||||
| PipelineElement::Or(_, expression) => expression,
|
| PipelineElement::Or(_, expression) => expression,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -789,16 +789,14 @@ pub fn eval_element_with_input(
|
|||||||
redirect_stderr: bool,
|
redirect_stderr: bool,
|
||||||
) -> Result<(PipelineData, bool), ShellError> {
|
) -> Result<(PipelineData, bool), ShellError> {
|
||||||
match element {
|
match element {
|
||||||
PipelineElement::Expression(_, expr) | PipelineElement::Or(_, expr) => {
|
PipelineElement::Expression(_, expr) => eval_expression_with_input(
|
||||||
eval_expression_with_input(
|
|
||||||
engine_state,
|
engine_state,
|
||||||
stack,
|
stack,
|
||||||
expr,
|
expr,
|
||||||
input,
|
input,
|
||||||
redirect_stdout,
|
redirect_stdout,
|
||||||
redirect_stderr,
|
redirect_stderr,
|
||||||
)
|
),
|
||||||
}
|
|
||||||
PipelineElement::Redirection(span, redirection, expr) => match &expr.expr {
|
PipelineElement::Redirection(span, redirection, expr) => match &expr.expr {
|
||||||
Expr::String(_) => {
|
Expr::String(_) => {
|
||||||
let input = match (redirection, input) {
|
let input = match (redirection, input) {
|
||||||
@ -905,6 +903,22 @@ pub fn eval_element_with_input(
|
|||||||
}
|
}
|
||||||
_ => Err(ShellError::CommandNotFound(*span)),
|
_ => Err(ShellError::CommandNotFound(*span)),
|
||||||
},
|
},
|
||||||
|
PipelineElement::And(_, expr) => eval_expression_with_input(
|
||||||
|
engine_state,
|
||||||
|
stack,
|
||||||
|
expr,
|
||||||
|
input,
|
||||||
|
redirect_stdout,
|
||||||
|
redirect_stderr,
|
||||||
|
),
|
||||||
|
PipelineElement::Or(_, expr) => eval_expression_with_input(
|
||||||
|
engine_state,
|
||||||
|
stack,
|
||||||
|
expr,
|
||||||
|
input,
|
||||||
|
redirect_stdout,
|
||||||
|
redirect_stderr,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -938,16 +952,10 @@ pub fn eval_block(
|
|||||||
redirect_stderr: bool,
|
redirect_stderr: bool,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let num_pipelines = block.len();
|
let num_pipelines = block.len();
|
||||||
let mut pipeline_idx = 0;
|
for (pipeline_idx, pipeline) in block.pipelines.iter().enumerate() {
|
||||||
|
|
||||||
while pipeline_idx < block.pipelines.len() {
|
|
||||||
let pipeline = &block.pipelines[pipeline_idx];
|
|
||||||
|
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
|
|
||||||
let mut last_element_is_pipeline_or = false;
|
while i < pipeline.elements.len() {
|
||||||
|
|
||||||
while i < pipeline.elements.len() && !last_element_is_pipeline_or {
|
|
||||||
let redirect_stderr = redirect_stderr
|
let redirect_stderr = redirect_stderr
|
||||||
|| ((i < pipeline.elements.len() - 1)
|
|| ((i < pipeline.elements.len() - 1)
|
||||||
&& (matches!(
|
&& (matches!(
|
||||||
@ -956,8 +964,6 @@ pub fn eval_block(
|
|||||||
| PipelineElement::Redirection(_, Redirection::StdoutAndStderr, _)
|
| PipelineElement::Redirection(_, Redirection::StdoutAndStderr, _)
|
||||||
)));
|
)));
|
||||||
|
|
||||||
last_element_is_pipeline_or = matches!(&pipeline.elements[i], PipelineElement::Or(..));
|
|
||||||
|
|
||||||
// if eval internal command failed, it can just make early return with `Err(ShellError)`.
|
// if eval internal command failed, it can just make early return with `Err(ShellError)`.
|
||||||
let eval_result = eval_element_with_input(
|
let eval_result = eval_element_with_input(
|
||||||
engine_state,
|
engine_state,
|
||||||
@ -984,16 +990,10 @@ pub fn eval_block(
|
|||||||
// don't return `Err(ShellError)`, so nushell wouldn't show extra error message.
|
// don't return `Err(ShellError)`, so nushell wouldn't show extra error message.
|
||||||
}
|
}
|
||||||
(Err(error), true) => input = PipelineData::Value(Value::Error { error }, None),
|
(Err(error), true) => input = PipelineData::Value(Value::Error { error }, None),
|
||||||
(output, false) if last_element_is_pipeline_or => match output {
|
|
||||||
Ok(output) => {
|
|
||||||
input = output.0;
|
|
||||||
}
|
|
||||||
Err(error) => input = PipelineData::Value(Value::Error { error }, None),
|
|
||||||
},
|
|
||||||
(output, false) => {
|
(output, false) => {
|
||||||
let output = output?;
|
let output = output?;
|
||||||
input = output.0;
|
input = output.0;
|
||||||
// external command may have failed
|
// external command may runs to failed
|
||||||
// make early return so remaining commands will not be executed.
|
// make early return so remaining commands will not be executed.
|
||||||
// don't return `Err(ShellError)`, so nushell wouldn't show extra error message.
|
// don't return `Err(ShellError)`, so nushell wouldn't show extra error message.
|
||||||
if output.1 {
|
if output.1 {
|
||||||
@ -1006,40 +1006,6 @@ pub fn eval_block(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if pipeline_idx < (num_pipelines) - 1 {
|
if pipeline_idx < (num_pipelines) - 1 {
|
||||||
if last_element_is_pipeline_or {
|
|
||||||
let input_is_error = matches!(input, PipelineData::Value(Value::Error { .. }, ..));
|
|
||||||
|
|
||||||
let result =
|
|
||||||
drain_and_print(engine_state, stack, input, redirect_stdout, redirect_stderr);
|
|
||||||
|
|
||||||
let last_exit_code = stack.last_exit_code(engine_state).unwrap_or(0);
|
|
||||||
|
|
||||||
if last_exit_code == 0 && result.is_ok() && !input_is_error {
|
|
||||||
// Skip the next pipeline ot run because this pipeline was successful and the
|
|
||||||
// user used the `a || b` connector
|
|
||||||
pipeline_idx += 1;
|
|
||||||
}
|
|
||||||
input = PipelineData::empty()
|
|
||||||
} else {
|
|
||||||
drain_and_print(engine_state, stack, input, redirect_stdout, redirect_stderr)?;
|
|
||||||
|
|
||||||
input = PipelineData::empty()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pipeline_idx += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn drain_and_print(
|
|
||||||
engine_state: &EngineState,
|
|
||||||
stack: &mut Stack,
|
|
||||||
mut input: PipelineData,
|
|
||||||
redirect_stdout: bool,
|
|
||||||
redirect_stderr: bool,
|
|
||||||
) -> Result<(), ShellError> {
|
|
||||||
match input {
|
match input {
|
||||||
PipelineData::Value(Value::Nothing { .. }, ..) => {}
|
PipelineData::Value(Value::Nothing { .. }, ..) => {}
|
||||||
PipelineData::ExternalStream {
|
PipelineData::ExternalStream {
|
||||||
@ -1093,8 +1059,12 @@ fn drain_and_print(
|
|||||||
redirect_stderr,
|
redirect_stderr,
|
||||||
)?;
|
)?;
|
||||||
} else {
|
} else {
|
||||||
let table =
|
let table = table.run(
|
||||||
table.run(engine_state, stack, &Call::new(Span::new(0, 0)), input)?;
|
engine_state,
|
||||||
|
stack,
|
||||||
|
&Call::new(Span::new(0, 0)),
|
||||||
|
input,
|
||||||
|
)?;
|
||||||
|
|
||||||
print_or_return(table, config)?;
|
print_or_return(table, config)?;
|
||||||
}
|
}
|
||||||
@ -1106,7 +1076,11 @@ fn drain_and_print(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
input = PipelineData::empty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_or_return(pipeline_data: PipelineData, config: &Config) -> Result<(), ShellError> {
|
fn print_or_return(pipeline_data: PipelineData, config: &Config) -> Result<(), ShellError> {
|
||||||
|
@ -455,10 +455,14 @@ pub fn flatten_pipeline_element(
|
|||||||
output.append(&mut flatten_expression(working_set, expr));
|
output.append(&mut flatten_expression(working_set, expr));
|
||||||
output
|
output
|
||||||
}
|
}
|
||||||
PipelineElement::Or(span, expr) => {
|
PipelineElement::And(span, expr) => {
|
||||||
let mut output = vec![];
|
let mut output = vec![(*span, FlatShape::And)];
|
||||||
|
output.append(&mut flatten_expression(working_set, expr));
|
||||||
|
output
|
||||||
|
}
|
||||||
|
PipelineElement::Or(span, expr) => {
|
||||||
|
let mut output = vec![(*span, FlatShape::Or)];
|
||||||
output.append(&mut flatten_expression(working_set, expr));
|
output.append(&mut flatten_expression(working_set, expr));
|
||||||
output.push((*span, FlatShape::Or));
|
|
||||||
output
|
output
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ pub enum TokenContents {
|
|||||||
Comment,
|
Comment,
|
||||||
Pipe,
|
Pipe,
|
||||||
PipePipe,
|
PipePipe,
|
||||||
AndAnd,
|
|
||||||
Semicolon,
|
Semicolon,
|
||||||
OutGreaterThan,
|
OutGreaterThan,
|
||||||
ErrGreaterThan,
|
ErrGreaterThan,
|
||||||
@ -255,10 +254,10 @@ pub fn lex_item(
|
|||||||
),
|
),
|
||||||
b"&&" => (
|
b"&&" => (
|
||||||
Token {
|
Token {
|
||||||
contents: TokenContents::AndAnd,
|
contents: TokenContents::Item,
|
||||||
span,
|
span,
|
||||||
},
|
},
|
||||||
None,
|
Some(ParseError::ShellAndAnd(span)),
|
||||||
),
|
),
|
||||||
b"2>" => (
|
b"2>" => (
|
||||||
Token {
|
Token {
|
||||||
|
@ -1420,9 +1420,7 @@ pub fn parse_module_block(
|
|||||||
|
|
||||||
pipeline
|
pipeline
|
||||||
}
|
}
|
||||||
LiteElement::Redirection(_, _, command) | LiteElement::Or(_, command) => {
|
LiteElement::Redirection(_, _, command) => garbage_pipeline(&command.parts),
|
||||||
garbage_pipeline(&command.parts)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
error = Some(ParseError::Expected("not a pipeline".into(), span));
|
error = Some(ParseError::Expected("not a pipeline".into(), span));
|
||||||
|
@ -1223,7 +1223,6 @@ fn parse_binary_with_base(
|
|||||||
}
|
}
|
||||||
TokenContents::Pipe
|
TokenContents::Pipe
|
||||||
| TokenContents::PipePipe
|
| TokenContents::PipePipe
|
||||||
| TokenContents::AndAnd
|
|
||||||
| TokenContents::OutGreaterThan
|
| TokenContents::OutGreaterThan
|
||||||
| TokenContents::ErrGreaterThan
|
| TokenContents::ErrGreaterThan
|
||||||
| TokenContents::OutErrGreaterThan => {
|
| TokenContents::OutErrGreaterThan => {
|
||||||
@ -3805,9 +3804,7 @@ pub fn parse_table_expression(
|
|||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
match &output.block[0].commands[0] {
|
match &output.block[0].commands[0] {
|
||||||
LiteElement::Command(_, command)
|
LiteElement::Command(_, command) | LiteElement::Redirection(_, _, command) => {
|
||||||
| LiteElement::Redirection(_, _, command)
|
|
||||||
| LiteElement::Or(_, command) => {
|
|
||||||
let mut table_headers = vec![];
|
let mut table_headers = vec![];
|
||||||
|
|
||||||
let (headers, err) = parse_value(
|
let (headers, err) = parse_value(
|
||||||
@ -3828,8 +3825,7 @@ pub fn parse_table_expression(
|
|||||||
|
|
||||||
match &output.block[1].commands[0] {
|
match &output.block[1].commands[0] {
|
||||||
LiteElement::Command(_, command)
|
LiteElement::Command(_, command)
|
||||||
| LiteElement::Redirection(_, _, command)
|
| LiteElement::Redirection(_, _, command) => {
|
||||||
| LiteElement::Or(_, command) => {
|
|
||||||
let mut rows = vec![];
|
let mut rows = vec![];
|
||||||
for part in &command.parts {
|
for part in &command.parts {
|
||||||
let (values, err) = parse_value(
|
let (values, err) = parse_value(
|
||||||
@ -5286,9 +5282,7 @@ pub fn parse_block(
|
|||||||
for pipeline in &lite_block.block {
|
for pipeline in &lite_block.block {
|
||||||
if pipeline.commands.len() == 1 {
|
if pipeline.commands.len() == 1 {
|
||||||
match &pipeline.commands[0] {
|
match &pipeline.commands[0] {
|
||||||
LiteElement::Command(_, command)
|
LiteElement::Command(_, command) | LiteElement::Redirection(_, _, command) => {
|
||||||
| LiteElement::Redirection(_, _, command)
|
|
||||||
| LiteElement::Or(_, command) => {
|
|
||||||
if let Some(err) =
|
if let Some(err) =
|
||||||
parse_def_predecl(working_set, &command.parts, expand_aliases_denylist)
|
parse_def_predecl(working_set, &command.parts, expand_aliases_denylist)
|
||||||
{
|
{
|
||||||
@ -5325,21 +5319,6 @@ pub fn parse_block(
|
|||||||
|
|
||||||
PipelineElement::Expression(*span, expr)
|
PipelineElement::Expression(*span, expr)
|
||||||
}
|
}
|
||||||
LiteElement::Or(span, command) => {
|
|
||||||
let (expr, err) = parse_expression(
|
|
||||||
working_set,
|
|
||||||
&command.parts,
|
|
||||||
expand_aliases_denylist,
|
|
||||||
is_subexpression,
|
|
||||||
);
|
|
||||||
working_set.type_scope.add_type(expr.ty.clone());
|
|
||||||
|
|
||||||
if error.is_none() {
|
|
||||||
error = err;
|
|
||||||
}
|
|
||||||
|
|
||||||
PipelineElement::Or(*span, expr)
|
|
||||||
}
|
|
||||||
LiteElement::Redirection(span, redirection, command) => {
|
LiteElement::Redirection(span, redirection, command) => {
|
||||||
trace!("parsing: pipeline element: redirection");
|
trace!("parsing: pipeline element: redirection");
|
||||||
let (expr, err) = parse_string(
|
let (expr, err) = parse_string(
|
||||||
@ -5375,16 +5354,8 @@ pub fn parse_block(
|
|||||||
|
|
||||||
Pipeline { elements: output }
|
Pipeline { elements: output }
|
||||||
} else {
|
} else {
|
||||||
let (mut pipeline, err) = match &pipeline.commands[0] {
|
match &pipeline.commands[0] {
|
||||||
LiteElement::Command(_, command) | LiteElement::Redirection(_, _, command) => {
|
LiteElement::Command(_, command) | LiteElement::Redirection(_, _, command) => {
|
||||||
parse_builtin_commands(
|
|
||||||
working_set,
|
|
||||||
command,
|
|
||||||
expand_aliases_denylist,
|
|
||||||
is_subexpression,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
LiteElement::Or(span, command) => {
|
|
||||||
let (mut pipeline, err) = parse_builtin_commands(
|
let (mut pipeline, err) = parse_builtin_commands(
|
||||||
working_set,
|
working_set,
|
||||||
command,
|
command,
|
||||||
@ -5392,17 +5363,10 @@ pub fn parse_block(
|
|||||||
is_subexpression,
|
is_subexpression,
|
||||||
);
|
);
|
||||||
|
|
||||||
if let PipelineElement::Expression(_, expr) = &pipeline.elements[0] {
|
|
||||||
pipeline.elements[0] = PipelineElement::Or(*span, expr.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
(pipeline, err)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if idx == 0 {
|
if idx == 0 {
|
||||||
if let Some(let_decl_id) = working_set.find_decl(b"let", &Type::Any) {
|
if let Some(let_decl_id) = working_set.find_decl(b"let", &Type::Any) {
|
||||||
if let Some(let_env_decl_id) = working_set.find_decl(b"let-env", &Type::Any)
|
if let Some(let_env_decl_id) =
|
||||||
|
working_set.find_decl(b"let-env", &Type::Any)
|
||||||
{
|
{
|
||||||
for element in pipeline.elements.iter_mut() {
|
for element in pipeline.elements.iter_mut() {
|
||||||
if let PipelineElement::Expression(
|
if let PipelineElement::Expression(
|
||||||
@ -5433,11 +5397,14 @@ pub fn parse_block(
|
|||||||
} else if element.has_in_variable(working_set)
|
} else if element.has_in_variable(working_set)
|
||||||
&& !is_subexpression
|
&& !is_subexpression
|
||||||
{
|
{
|
||||||
*element = wrap_element_with_collect(working_set, element);
|
*element =
|
||||||
|
wrap_element_with_collect(working_set, element);
|
||||||
}
|
}
|
||||||
} else if element.has_in_variable(working_set) && !is_subexpression
|
} else if element.has_in_variable(working_set)
|
||||||
|
&& !is_subexpression
|
||||||
{
|
{
|
||||||
*element = wrap_element_with_collect(working_set, element);
|
*element =
|
||||||
|
wrap_element_with_collect(working_set, element);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5450,6 +5417,8 @@ pub fn parse_block(
|
|||||||
|
|
||||||
pipeline
|
pipeline
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.into();
|
.into();
|
||||||
|
|
||||||
@ -5525,6 +5494,7 @@ pub fn discover_captures_in_pipeline_element(
|
|||||||
match element {
|
match element {
|
||||||
PipelineElement::Expression(_, expression)
|
PipelineElement::Expression(_, expression)
|
||||||
| PipelineElement::Redirection(_, _, expression)
|
| PipelineElement::Redirection(_, _, expression)
|
||||||
|
| PipelineElement::And(_, expression)
|
||||||
| PipelineElement::Or(_, expression) => {
|
| PipelineElement::Or(_, expression) => {
|
||||||
discover_captures_in_expr(working_set, expression, seen, seen_blocks)
|
discover_captures_in_expr(working_set, expression, seen, seen_blocks)
|
||||||
}
|
}
|
||||||
@ -5785,6 +5755,9 @@ fn wrap_element_with_collect(
|
|||||||
wrap_expr_with_collect(working_set, expression),
|
wrap_expr_with_collect(working_set, expression),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
PipelineElement::And(span, expression) => {
|
||||||
|
PipelineElement::And(*span, wrap_expr_with_collect(working_set, expression))
|
||||||
|
}
|
||||||
PipelineElement::Or(span, expression) => {
|
PipelineElement::Or(span, expression) => {
|
||||||
PipelineElement::Or(*span, wrap_expr_with_collect(working_set, expression))
|
PipelineElement::Or(*span, wrap_expr_with_collect(working_set, expression))
|
||||||
}
|
}
|
||||||
@ -5888,7 +5861,6 @@ impl LiteCommand {
|
|||||||
pub enum LiteElement {
|
pub enum LiteElement {
|
||||||
Command(Option<Span>, LiteCommand),
|
Command(Option<Span>, LiteCommand),
|
||||||
Redirection(Span, Redirection, LiteCommand),
|
Redirection(Span, Redirection, LiteCommand),
|
||||||
Or(Span, LiteCommand),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -5957,8 +5929,15 @@ pub fn lite_parse(tokens: &[Token]) -> (LiteBlock, Option<ParseError>) {
|
|||||||
|
|
||||||
let mut curr_comment: Option<Vec<Span>> = None;
|
let mut curr_comment: Option<Vec<Span>> = None;
|
||||||
|
|
||||||
|
let mut error = None;
|
||||||
|
|
||||||
for token in tokens.iter() {
|
for token in tokens.iter() {
|
||||||
match &token.contents {
|
match &token.contents {
|
||||||
|
TokenContents::PipePipe => {
|
||||||
|
error = error.or(Some(ParseError::ShellOrOr(token.span)));
|
||||||
|
curr_command.push(token.span);
|
||||||
|
last_token = TokenContents::Item;
|
||||||
|
}
|
||||||
TokenContents::Item => {
|
TokenContents::Item => {
|
||||||
// If we have a comment, go ahead and attach it
|
// If we have a comment, go ahead and attach it
|
||||||
if let Some(curr_comment) = curr_comment.take() {
|
if let Some(curr_comment) = curr_comment.take() {
|
||||||
@ -6094,25 +6073,7 @@ pub fn lite_parse(tokens: &[Token]) -> (LiteBlock, Option<ParseError>) {
|
|||||||
|
|
||||||
last_token = TokenContents::Eol;
|
last_token = TokenContents::Eol;
|
||||||
}
|
}
|
||||||
TokenContents::PipePipe => {
|
TokenContents::Semicolon => {
|
||||||
// Different to redirection, for PipePipe, we'll wrap the current command
|
|
||||||
// in an "Or". This lets us know during eval that it's the current command
|
|
||||||
// whose error will be ignored rather than having to look ahead in the pipeline
|
|
||||||
if !curr_command.is_empty() {
|
|
||||||
curr_pipeline.push(LiteElement::Or(token.span, curr_command));
|
|
||||||
curr_command = LiteCommand::new();
|
|
||||||
}
|
|
||||||
if !curr_pipeline.is_empty() {
|
|
||||||
block.push(curr_pipeline);
|
|
||||||
|
|
||||||
curr_pipeline = LitePipeline::new();
|
|
||||||
last_connector = TokenContents::Pipe;
|
|
||||||
last_connector_span = None;
|
|
||||||
}
|
|
||||||
|
|
||||||
last_token = TokenContents::PipePipe;
|
|
||||||
}
|
|
||||||
TokenContents::Semicolon | TokenContents::AndAnd => {
|
|
||||||
if !curr_command.is_empty() {
|
if !curr_command.is_empty() {
|
||||||
match last_connector {
|
match last_connector {
|
||||||
TokenContents::OutGreaterThan => {
|
TokenContents::OutGreaterThan => {
|
||||||
@ -6141,7 +6102,7 @@ pub fn lite_parse(tokens: &[Token]) -> (LiteBlock, Option<ParseError>) {
|
|||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
curr_pipeline
|
curr_pipeline
|
||||||
.push(LiteElement::Command(Some(token.span), curr_command));
|
.push(LiteElement::Command(last_connector_span, curr_command));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6213,10 +6174,7 @@ pub fn lite_parse(tokens: &[Token]) -> (LiteBlock, Option<ParseError>) {
|
|||||||
block.push(curr_pipeline);
|
block.push(curr_pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
if last_token == TokenContents::Pipe
|
if last_token == TokenContents::Pipe {
|
||||||
|| last_token == TokenContents::PipePipe
|
|
||||||
|| last_token == TokenContents::AndAnd
|
|
||||||
{
|
|
||||||
(
|
(
|
||||||
block,
|
block,
|
||||||
Some(ParseError::UnexpectedEof(
|
Some(ParseError::UnexpectedEof(
|
||||||
@ -6225,7 +6183,7 @@ pub fn lite_parse(tokens: &[Token]) -> (LiteBlock, Option<ParseError>) {
|
|||||||
)),
|
)),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
(block, None)
|
(block, error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ pub enum Redirection {
|
|||||||
pub enum PipelineElement {
|
pub enum PipelineElement {
|
||||||
Expression(Option<Span>, Expression),
|
Expression(Option<Span>, Expression),
|
||||||
Redirection(Span, Redirection, Expression),
|
Redirection(Span, Redirection, Expression),
|
||||||
|
And(Span, Expression),
|
||||||
Or(Span, Expression),
|
Or(Span, Expression),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -22,8 +23,9 @@ impl PipelineElement {
|
|||||||
match self {
|
match self {
|
||||||
PipelineElement::Expression(None, expression) => expression.span,
|
PipelineElement::Expression(None, expression) => expression.span,
|
||||||
PipelineElement::Expression(Some(span), expression)
|
PipelineElement::Expression(Some(span), expression)
|
||||||
| PipelineElement::Or(span, expression)
|
| PipelineElement::Redirection(span, _, expression)
|
||||||
| PipelineElement::Redirection(span, _, expression) => Span {
|
| PipelineElement::And(span, expression)
|
||||||
|
| PipelineElement::Or(span, expression) => Span {
|
||||||
start: span.start,
|
start: span.start,
|
||||||
end: expression.span.end,
|
end: expression.span.end,
|
||||||
},
|
},
|
||||||
@ -33,6 +35,7 @@ impl PipelineElement {
|
|||||||
match self {
|
match self {
|
||||||
PipelineElement::Expression(_, expression)
|
PipelineElement::Expression(_, expression)
|
||||||
| PipelineElement::Redirection(_, _, expression)
|
| PipelineElement::Redirection(_, _, expression)
|
||||||
|
| PipelineElement::And(_, expression)
|
||||||
| PipelineElement::Or(_, expression) => expression.has_in_variable(working_set),
|
| PipelineElement::Or(_, expression) => expression.has_in_variable(working_set),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -40,8 +43,9 @@ impl PipelineElement {
|
|||||||
pub fn replace_in_variable(&mut self, working_set: &mut StateWorkingSet, new_var_id: VarId) {
|
pub fn replace_in_variable(&mut self, working_set: &mut StateWorkingSet, new_var_id: VarId) {
|
||||||
match self {
|
match self {
|
||||||
PipelineElement::Expression(_, expression)
|
PipelineElement::Expression(_, expression)
|
||||||
| PipelineElement::Or(_, expression)
|
| PipelineElement::Redirection(_, _, expression)
|
||||||
| PipelineElement::Redirection(_, _, expression) => {
|
| PipelineElement::And(_, expression)
|
||||||
|
| PipelineElement::Or(_, expression) => {
|
||||||
expression.replace_in_variable(working_set, new_var_id)
|
expression.replace_in_variable(working_set, new_var_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -55,8 +59,9 @@ impl PipelineElement {
|
|||||||
) {
|
) {
|
||||||
match self {
|
match self {
|
||||||
PipelineElement::Expression(_, expression)
|
PipelineElement::Expression(_, expression)
|
||||||
| PipelineElement::Or(_, expression)
|
| PipelineElement::Redirection(_, _, expression)
|
||||||
| PipelineElement::Redirection(_, _, expression) => {
|
| PipelineElement::And(_, expression)
|
||||||
|
| PipelineElement::Or(_, expression) => {
|
||||||
expression.replace_span(working_set, replaced, new_span)
|
expression.replace_span(working_set, replaced, new_span)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,13 +113,6 @@ impl Stack {
|
|||||||
.ok_or_else(|| ShellError::NushellFailed("No active overlay".into()))
|
.ok_or_else(|| ShellError::NushellFailed("No active overlay".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn last_exit_code(&self, engine_state: &EngineState) -> Option<i64> {
|
|
||||||
match self.get_env_var(engine_state, "LAST_EXIT_CODE") {
|
|
||||||
Some(Value::Int { val, .. }) => Some(val),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn captures_to_stack(&self, captures: &HashMap<VarId, Value>) -> Stack {
|
pub fn captures_to_stack(&self, captures: &HashMap<VarId, Value>) -> Stack {
|
||||||
// FIXME: this is probably slow
|
// FIXME: this is probably slow
|
||||||
let mut env_vars = self.env_vars.clone();
|
let mut env_vars = self.env_vars.clone();
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
mod commands;
|
mod commands;
|
||||||
mod pipeline_operators;
|
|
||||||
|
|
||||||
use nu_test_support::nu;
|
use nu_test_support::nu;
|
||||||
|
|
||||||
|
@ -1,74 +0,0 @@
|
|||||||
use nu_test_support::nu;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn and_operator1() {
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: ".",
|
|
||||||
r#"
|
|
||||||
3 / 0 && 2 + 3
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
|
|
||||||
assert!(actual.err.contains("division by zero"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn and_operator2() {
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: ".",
|
|
||||||
r#"
|
|
||||||
0 | 3 / $in && 2 + 3
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
|
|
||||||
assert!(actual.err.contains("division by zero"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn or_operator1() {
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: ".",
|
|
||||||
r#"
|
|
||||||
3 / 0 || 2 + 3
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
|
|
||||||
assert!(actual.out.contains('5'));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn or_operator2() {
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: ".",
|
|
||||||
r#"
|
|
||||||
0 | 3 / $in || 2 + 3
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
|
|
||||||
assert!(actual.out.contains('5'));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn or_operator3() {
|
|
||||||
// On success, don't run the next step
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: ".",
|
|
||||||
r#"
|
|
||||||
0 || 2 + 3
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(actual.out, "0");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn or_operator4() {
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: ".",
|
|
||||||
r#"
|
|
||||||
1 / 0 || 2 / 0 || 10 + 9
|
|
||||||
"#
|
|
||||||
);
|
|
||||||
|
|
||||||
assert!(actual.out.contains("19"));
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user