Add unary not (#5111)

This commit is contained in:
JT 2022-04-07 07:10:25 +12:00 committed by GitHub
parent 12d3e4e424
commit 591fb4bd36
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 115 additions and 1 deletions

View File

@ -111,6 +111,7 @@ impl Command for Glob {
}
};
#[allow(clippy::needless_collect)]
let glob_results: Vec<Value> = glob
.walk(path, folder_depth)
.flatten()

View File

@ -195,6 +195,12 @@ fn convert_to_value(
"binary operators not supported in nuon".into(),
expr.span,
)),
Expr::UnaryNot(..) => Err(ShellError::OutsideSpannedLabeledError(
original_text.to_string(),
"Error when loading".into(),
"unary operators not supported in nuon".into(),
expr.span,
)),
Expr::Block(..) => Err(ShellError::OutsideSpannedLabeledError(
original_text.to_string(),
"Error when loading".into(),

View File

@ -319,6 +319,16 @@ pub fn eval_expression(
span: expr.span,
}),
Expr::Operator(_) => Ok(Value::Nothing { span: expr.span }),
Expr::UnaryNot(expr) => {
let lhs = eval_expression(engine_state, stack, expr)?;
match lhs {
Value::Bool { val, .. } => Ok(Value::Bool {
val: !val,
span: expr.span,
}),
_ => Err(ShellError::TypeMismatch("bool".to_string(), expr.span)),
}
}
Expr::BinaryOp(lhs, op, rhs) => {
let op_span = op.span;
let lhs = eval_expression(engine_state, stack, lhs)?;

View File

@ -88,6 +88,17 @@ pub fn flatten_expression(
output.extend(flatten_expression(working_set, rhs));
output
}
Expr::UnaryNot(inner_expr) => {
let mut output = vec![(
Span {
start: expr.span.start,
end: expr.span.start + 3,
},
FlatShape::Operator,
)];
output.extend(flatten_expression(working_set, inner_expr));
output
}
Expr::Block(block_id) | Expr::RowCondition(block_id) | Expr::Subexpression(block_id) => {
let outer_span = expr.span;

View File

@ -49,7 +49,7 @@ pub fn is_math_expression_like(bytes: &[u8]) -> bool {
return false;
}
if bytes == b"true" || bytes == b"false" || bytes == b"null" {
if bytes == b"true" || bytes == b"false" || bytes == b"null" || bytes == b"not" {
return true;
}
@ -872,6 +872,10 @@ pub fn parse_call(
let bytes = working_set.get_span_contents(*word_span);
if is_math_expression_like(bytes)
&& bytes != b"true"
&& bytes != b"false"
&& bytes != b"null"
&& bytes != b"not"
&& !working_set
.permanent_state
.external_exceptions
@ -4005,6 +4009,40 @@ pub fn parse_math_expression(
let mut last_prec = 1000000;
let mut error = None;
let first_span = working_set.get_span_contents(spans[0]);
if first_span == b"not" {
if spans.len() > 1 {
let (remainder, err) = parse_math_expression(
working_set,
&spans[1..],
lhs_row_var_id,
expand_aliases_denylist,
);
return (
Expression {
expr: Expr::UnaryNot(Box::new(remainder)),
span: span(spans),
ty: Type::Bool,
custom_completion: None,
},
err,
);
} else {
return (
garbage(spans[0]),
Some(ParseError::Expected(
"expression".into(),
Span {
start: spans[0].end,
end: spans[0].end,
},
)),
);
}
}
let (mut lhs, err) = parse_value(
working_set,
spans[0],
@ -4716,6 +4754,10 @@ pub fn discover_captures_in_expr(
output.extend(&lhs_result);
output.extend(&rhs_result);
}
Expr::UnaryNot(expr) => {
let result = discover_captures_in_expr(working_set, expr, seen, seen_blocks);
output.extend(&result);
}
Expr::Block(block_id) => {
let block = working_set.get_block(*block_id);
let results = {

View File

@ -22,6 +22,7 @@ pub enum Expr {
ExternalCall(Box<Expression>, Vec<Expression>),
Operator(Operator),
RowCondition(BlockId),
UnaryNot(Box<Expression>),
BinaryOp(Box<Expression>, Box<Expression>, Box<Expression>), //lhs, op, rhs
Subexpression(BlockId),
Block(BlockId),

View File

@ -113,6 +113,7 @@ impl Expression {
Expr::BinaryOp(left, _, right) => {
left.has_in_variable(working_set) || right.has_in_variable(working_set)
}
Expr::UnaryNot(expr) => expr.has_in_variable(working_set),
Expr::Block(block_id) => {
let block = working_set.get_block(*block_id);
@ -264,6 +265,9 @@ impl Expression {
left.replace_in_variable(working_set, new_var_id);
right.replace_in_variable(working_set, new_var_id);
}
Expr::UnaryNot(expr) => {
expr.replace_in_variable(working_set, new_var_id);
}
Expr::Block(block_id) => {
let block = working_set.get_block(*block_id);
@ -425,6 +429,9 @@ impl Expression {
left.replace_span(working_set, replaced, new_span);
right.replace_span(working_set, replaced, new_span);
}
Expr::UnaryNot(expr) => {
expr.replace_span(working_set, replaced, new_span);
}
Expr::Block(block_id) => {
let mut block = working_set.get_block(*block_id).clone();

View File

@ -375,3 +375,39 @@ fn single_value_row_condition() -> TestResult {
"2",
)
}
#[test]
fn unary_not_1() -> TestResult {
run_test(r#"not false"#, "true")
}
#[test]
fn unary_not_2() -> TestResult {
run_test(r#"not (false)"#, "true")
}
#[test]
fn unary_not_3() -> TestResult {
run_test(r#"(not false)"#, "true")
}
#[test]
fn unary_not_4() -> TestResult {
run_test(r#"if not false { "hello" } else { "world" }"#, "hello")
}
#[test]
fn unary_not_5() -> TestResult {
run_test(
r#"if not not not not false { "hello" } else { "world" }"#,
"world",
)
}
#[test]
fn unary_not_6() -> TestResult {
run_test(
r#"[[name, present]; [abc, true], [def, false]] | where not present | get name.0"#,
"def",
)
}