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:
JT
2022-12-13 16:36:13 +13:00
committed by GitHub
parent b7a3e5989d
commit 0c656fd276
12 changed files with 180 additions and 321 deletions

View File

@ -455,10 +455,14 @@ pub fn flatten_pipeline_element(
output.append(&mut flatten_expression(working_set, expr));
output
}
PipelineElement::Or(span, expr) => {
let mut output = vec![];
PipelineElement::And(span, expr) => {
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.push((*span, FlatShape::Or));
output
}
}

View File

@ -7,7 +7,6 @@ pub enum TokenContents {
Comment,
Pipe,
PipePipe,
AndAnd,
Semicolon,
OutGreaterThan,
ErrGreaterThan,
@ -255,10 +254,10 @@ pub fn lex_item(
),
b"&&" => (
Token {
contents: TokenContents::AndAnd,
contents: TokenContents::Item,
span,
},
None,
Some(ParseError::ShellAndAnd(span)),
),
b"2>" => (
Token {

View File

@ -1420,9 +1420,7 @@ pub fn parse_module_block(
pipeline
}
LiteElement::Redirection(_, _, command) | LiteElement::Or(_, command) => {
garbage_pipeline(&command.parts)
}
LiteElement::Redirection(_, _, command) => garbage_pipeline(&command.parts),
}
} else {
error = Some(ParseError::Expected("not a pipeline".into(), span));

View File

@ -1223,7 +1223,6 @@ fn parse_binary_with_base(
}
TokenContents::Pipe
| TokenContents::PipePipe
| TokenContents::AndAnd
| TokenContents::OutGreaterThan
| TokenContents::ErrGreaterThan
| TokenContents::OutErrGreaterThan => {
@ -3805,9 +3804,7 @@ pub fn parse_table_expression(
}
_ => {
match &output.block[0].commands[0] {
LiteElement::Command(_, command)
| LiteElement::Redirection(_, _, command)
| LiteElement::Or(_, command) => {
LiteElement::Command(_, command) | LiteElement::Redirection(_, _, command) => {
let mut table_headers = vec![];
let (headers, err) = parse_value(
@ -3828,8 +3825,7 @@ pub fn parse_table_expression(
match &output.block[1].commands[0] {
LiteElement::Command(_, command)
| LiteElement::Redirection(_, _, command)
| LiteElement::Or(_, command) => {
| LiteElement::Redirection(_, _, command) => {
let mut rows = vec![];
for part in &command.parts {
let (values, err) = parse_value(
@ -5286,9 +5282,7 @@ pub fn parse_block(
for pipeline in &lite_block.block {
if pipeline.commands.len() == 1 {
match &pipeline.commands[0] {
LiteElement::Command(_, command)
| LiteElement::Redirection(_, _, command)
| LiteElement::Or(_, command) => {
LiteElement::Command(_, command) | LiteElement::Redirection(_, _, command) => {
if let Some(err) =
parse_def_predecl(working_set, &command.parts, expand_aliases_denylist)
{
@ -5325,21 +5319,6 @@ pub fn parse_block(
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) => {
trace!("parsing: pipeline element: redirection");
let (expr, err) = parse_string(
@ -5375,16 +5354,8 @@ pub fn parse_block(
Pipeline { elements: output }
} else {
let (mut pipeline, err) = match &pipeline.commands[0] {
match &pipeline.commands[0] {
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(
working_set,
command,
@ -5392,63 +5363,61 @@ pub fn parse_block(
is_subexpression,
);
if let PipelineElement::Expression(_, expr) = &pipeline.elements[0] {
pipeline.elements[0] = PipelineElement::Or(*span, expr.clone())
}
(pipeline, err)
}
};
if idx == 0 {
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)
{
for element in pipeline.elements.iter_mut() {
if let PipelineElement::Expression(
_,
Expression {
expr: Expr::Call(call),
..
},
) = element
if idx == 0 {
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 call.decl_id == let_decl_id
|| call.decl_id == let_env_decl_id
{
// Do an expansion
if let Some(Expression {
expr: Expr::Keyword(_, _, expr),
..
}) = call.positional_iter_mut().nth(1)
for element in pipeline.elements.iter_mut() {
if let PipelineElement::Expression(
_,
Expression {
expr: Expr::Call(call),
..
},
) = element
{
if expr.has_in_variable(working_set) {
*expr = Box::new(wrap_expr_with_collect(
working_set,
expr,
));
if call.decl_id == let_decl_id
|| call.decl_id == let_env_decl_id
{
// Do an expansion
if let Some(Expression {
expr: Expr::Keyword(_, _, expr),
..
}) = call.positional_iter_mut().nth(1)
{
if expr.has_in_variable(working_set) {
*expr = Box::new(wrap_expr_with_collect(
working_set,
expr,
));
}
}
continue;
} else if element.has_in_variable(working_set)
&& !is_subexpression
{
*element =
wrap_element_with_collect(working_set, element);
}
} else if element.has_in_variable(working_set)
&& !is_subexpression
{
*element =
wrap_element_with_collect(working_set, element);
}
continue;
} else if element.has_in_variable(working_set)
&& !is_subexpression
{
*element = wrap_element_with_collect(working_set, element);
}
} else if element.has_in_variable(working_set) && !is_subexpression
{
*element = wrap_element_with_collect(working_set, element);
}
}
}
if error.is_none() {
error = err;
}
pipeline
}
}
if error.is_none() {
error = err;
}
pipeline
}
})
.into();
@ -5525,6 +5494,7 @@ pub fn discover_captures_in_pipeline_element(
match element {
PipelineElement::Expression(_, expression)
| PipelineElement::Redirection(_, _, expression)
| PipelineElement::And(_, expression)
| PipelineElement::Or(_, expression) => {
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),
)
}
PipelineElement::And(span, expression) => {
PipelineElement::And(*span, wrap_expr_with_collect(working_set, expression))
}
PipelineElement::Or(span, expression) => {
PipelineElement::Or(*span, wrap_expr_with_collect(working_set, expression))
}
@ -5888,7 +5861,6 @@ impl LiteCommand {
pub enum LiteElement {
Command(Option<Span>, LiteCommand),
Redirection(Span, Redirection, LiteCommand),
Or(Span, LiteCommand),
}
#[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 error = None;
for token in tokens.iter() {
match &token.contents {
TokenContents::PipePipe => {
error = error.or(Some(ParseError::ShellOrOr(token.span)));
curr_command.push(token.span);
last_token = TokenContents::Item;
}
TokenContents::Item => {
// If we have a comment, go ahead and attach it
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;
}
TokenContents::PipePipe => {
// 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 => {
TokenContents::Semicolon => {
if !curr_command.is_empty() {
match last_connector {
TokenContents::OutGreaterThan => {
@ -6141,7 +6102,7 @@ pub fn lite_parse(tokens: &[Token]) -> (LiteBlock, Option<ParseError>) {
}
_ => {
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);
}
if last_token == TokenContents::Pipe
|| last_token == TokenContents::PipePipe
|| last_token == TokenContents::AndAnd
{
if last_token == TokenContents::Pipe {
(
block,
Some(ParseError::UnexpectedEof(
@ -6225,7 +6183,7 @@ pub fn lite_parse(tokens: &[Token]) -> (LiteBlock, Option<ParseError>) {
)),
)
} else {
(block, None)
(block, error)
}
}