Fix known externals, fix operator spans (#5140)

This commit is contained in:
JT 2022-04-09 17:17:48 +12:00 committed by GitHub
parent 683b912263
commit 14066ccc30
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 186 additions and 127 deletions

View File

@ -305,13 +305,13 @@ fn find_with_rest(
| Value::Block { .. } | Value::Block { .. }
| Value::Nothing { .. } | Value::Nothing { .. }
| Value::Error { .. } => lower_value | Value::Error { .. } => lower_value
.eq(span, term) .eq(span, term, span)
.map_or(false, |value| value.is_true()), .map_or(false, |value| value.is_true()),
Value::String { .. } Value::String { .. }
| Value::List { .. } | Value::List { .. }
| Value::CellPath { .. } | Value::CellPath { .. }
| Value::CustomValue { .. } => term | Value::CustomValue { .. } => term
.r#in(span, &lower_value) .r#in(span, &lower_value, span)
.map_or(false, |value| value.is_true()), .map_or(false, |value| value.is_true()),
Value::Record { vals, .. } => vals.iter().any(|val| { Value::Record { vals, .. } => vals.iter().any(|val| {
if let Ok(span) = val.span() { if let Ok(span) = val.span() {
@ -320,10 +320,11 @@ fn find_with_rest(
Span::test_data(), Span::test_data(),
); );
term.r#in(span, &lower_val) term.r#in(span, &lower_val, span)
.map_or(false, |value| value.is_true()) .map_or(false, |value| value.is_true())
} else { } else {
term.r#in(span, val).map_or(false, |value| value.is_true()) term.r#in(span, val, span)
.map_or(false, |value| value.is_true())
} }
}), }),
Value::Binary { .. } => false, Value::Binary { .. } => false,

View File

@ -67,6 +67,7 @@ pub fn average(values: &[Value], head: &Span) -> Result<Value, ShellError> {
val: values.len() as i64, val: values.len() as i64,
span: *head, span: *head,
}, },
*head,
), ),
} }
} }

View File

@ -98,7 +98,7 @@ pub fn sum(data: Vec<Value>, head: Span) -> Result<Value, ShellError> {
| Value::Float { .. } | Value::Float { .. }
| Value::Filesize { .. } | Value::Filesize { .. }
| Value::Duration { .. } => { | Value::Duration { .. } => {
acc = acc.add(head, value)?; acc = acc.add(head, value, head)?;
} }
other => { other => {
return Err(ShellError::UnsupportedInput( return Err(ShellError::UnsupportedInput(
@ -129,7 +129,7 @@ pub fn product(data: Vec<Value>, head: Span) -> Result<Value, ShellError> {
for value in &data { for value in &data {
match value { match value {
Value::Int { .. } | Value::Float { .. } => { Value::Int { .. } | Value::Float { .. } => {
acc = acc.mul(head, value)?; acc = acc.mul(head, value, head)?;
} }
other => { other => {
return Err(ShellError::UnsupportedInput( return Err(ShellError::UnsupportedInput(

View File

@ -78,15 +78,15 @@ fn sum_of_squares(values: &[Value], span: &Span) -> Result<Value, ShellError> {
value.span().unwrap_or(*span), value.span().unwrap_or(*span),
)) ))
}?; }?;
let v_squared = &v.mul(*span, v)?; let v_squared = &v.mul(*span, v, *span)?;
sum_x2 = sum_x2.add(*span, v_squared)?; sum_x2 = sum_x2.add(*span, v_squared, *span)?;
sum_x = sum_x.add(*span, v)?; sum_x = sum_x.add(*span, v, *span)?;
} }
let sum_x_squared = sum_x.mul(*span, &sum_x)?; let sum_x_squared = sum_x.mul(*span, &sum_x, *span)?;
let sum_x_squared_div_n = sum_x_squared.div(*span, &n)?; let sum_x_squared_div_n = sum_x_squared.div(*span, &n, *span)?;
let ss = sum_x2.sub(*span, &sum_x_squared_div_n)?; let ss = sum_x2.sub(*span, &sum_x_squared_div_n, *span)?;
Ok(ss) Ok(ss)
} }
@ -111,7 +111,7 @@ pub fn compute_variance(sample: bool) -> impl Fn(&[Value], &Span) -> Result<Valu
val: n as i64, val: n as i64,
span: *span, span: *span,
}; };
ss.div(*span, &n) ss.div(*span, &n, *span)
} }
} }

View File

@ -65,7 +65,7 @@ impl Command for KeybindingsList {
.collect() .collect()
} else { } else {
call.named_iter() call.named_iter()
.flat_map(|(argument, _)| get_records(argument.item.as_str(), &call.head)) .flat_map(|(argument, _, _)| get_records(argument.item.as_str(), &call.head))
.collect() .collect()
}; };

View File

@ -32,7 +32,7 @@ pub fn eval_call(
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
let decl = engine_state.get_decl(call.decl_id); let decl = engine_state.get_decl(call.decl_id);
if !decl.is_known_external() && call.named_iter().any(|(flag, _)| flag.item == "help") { if !decl.is_known_external() && call.named_iter().any(|(flag, _, _)| flag.item == "help") {
let mut signature = decl.signature(); let mut signature = decl.signature();
signature.usage = decl.usage().to_string(); signature.usage = decl.usage().to_string();
signature.extra_usage = decl.extra_usage().to_string(); signature.extra_usage = decl.extra_usage().to_string();
@ -103,7 +103,7 @@ pub fn eval_call(
let mut found = false; let mut found = false;
for call_named in call.named_iter() { for call_named in call.named_iter() {
if call_named.0.item == named.long { if call_named.0.item == named.long {
if let Some(arg) = &call_named.1 { if let Some(arg) = &call_named.2 {
let result = eval_expression(engine_state, caller_stack, arg)?; let result = eval_expression(engine_state, caller_stack, arg)?;
callee_stack.add_var(var_id, result); callee_stack.add_var(var_id, result);
@ -211,6 +211,7 @@ fn eval_external(
span: head.span, span: head.span,
}, },
None, None,
None,
)) ))
} }
@ -221,6 +222,7 @@ fn eval_external(
span: head.span, span: head.span,
}, },
None, None,
None,
)) ))
} }
@ -343,7 +345,7 @@ pub fn eval_expression(
}) })
} else { } else {
let rhs = eval_expression(engine_state, stack, rhs)?; let rhs = eval_expression(engine_state, stack, rhs)?;
lhs.and(op_span, &rhs) lhs.and(op_span, &rhs, expr.span)
} }
} }
Operator::Or => { Operator::Or => {
@ -354,76 +356,76 @@ pub fn eval_expression(
}) })
} else { } else {
let rhs = eval_expression(engine_state, stack, rhs)?; let rhs = eval_expression(engine_state, stack, rhs)?;
lhs.or(op_span, &rhs) lhs.or(op_span, &rhs, expr.span)
} }
} }
Operator::Plus => { Operator::Plus => {
let rhs = eval_expression(engine_state, stack, rhs)?; let rhs = eval_expression(engine_state, stack, rhs)?;
lhs.add(op_span, &rhs) lhs.add(op_span, &rhs, expr.span)
} }
Operator::Minus => { Operator::Minus => {
let rhs = eval_expression(engine_state, stack, rhs)?; let rhs = eval_expression(engine_state, stack, rhs)?;
lhs.sub(op_span, &rhs) lhs.sub(op_span, &rhs, expr.span)
} }
Operator::Multiply => { Operator::Multiply => {
let rhs = eval_expression(engine_state, stack, rhs)?; let rhs = eval_expression(engine_state, stack, rhs)?;
lhs.mul(op_span, &rhs) lhs.mul(op_span, &rhs, expr.span)
} }
Operator::Divide => { Operator::Divide => {
let rhs = eval_expression(engine_state, stack, rhs)?; let rhs = eval_expression(engine_state, stack, rhs)?;
lhs.div(op_span, &rhs) lhs.div(op_span, &rhs, expr.span)
} }
Operator::LessThan => { Operator::LessThan => {
let rhs = eval_expression(engine_state, stack, rhs)?; let rhs = eval_expression(engine_state, stack, rhs)?;
lhs.lt(op_span, &rhs) lhs.lt(op_span, &rhs, expr.span)
} }
Operator::LessThanOrEqual => { Operator::LessThanOrEqual => {
let rhs = eval_expression(engine_state, stack, rhs)?; let rhs = eval_expression(engine_state, stack, rhs)?;
lhs.lte(op_span, &rhs) lhs.lte(op_span, &rhs, expr.span)
} }
Operator::GreaterThan => { Operator::GreaterThan => {
let rhs = eval_expression(engine_state, stack, rhs)?; let rhs = eval_expression(engine_state, stack, rhs)?;
lhs.gt(op_span, &rhs) lhs.gt(op_span, &rhs, expr.span)
} }
Operator::GreaterThanOrEqual => { Operator::GreaterThanOrEqual => {
let rhs = eval_expression(engine_state, stack, rhs)?; let rhs = eval_expression(engine_state, stack, rhs)?;
lhs.gte(op_span, &rhs) lhs.gte(op_span, &rhs, expr.span)
} }
Operator::Equal => { Operator::Equal => {
let rhs = eval_expression(engine_state, stack, rhs)?; let rhs = eval_expression(engine_state, stack, rhs)?;
lhs.eq(op_span, &rhs) lhs.eq(op_span, &rhs, expr.span)
} }
Operator::NotEqual => { Operator::NotEqual => {
let rhs = eval_expression(engine_state, stack, rhs)?; let rhs = eval_expression(engine_state, stack, rhs)?;
lhs.ne(op_span, &rhs) lhs.ne(op_span, &rhs, expr.span)
} }
Operator::In => { Operator::In => {
let rhs = eval_expression(engine_state, stack, rhs)?; let rhs = eval_expression(engine_state, stack, rhs)?;
lhs.r#in(op_span, &rhs) lhs.r#in(op_span, &rhs, expr.span)
} }
Operator::NotIn => { Operator::NotIn => {
let rhs = eval_expression(engine_state, stack, rhs)?; let rhs = eval_expression(engine_state, stack, rhs)?;
lhs.not_in(op_span, &rhs) lhs.not_in(op_span, &rhs, expr.span)
} }
Operator::RegexMatch => { Operator::RegexMatch => {
let rhs = eval_expression(engine_state, stack, rhs)?; let rhs = eval_expression(engine_state, stack, rhs)?;
lhs.regex_match(op_span, &rhs, false) lhs.regex_match(op_span, &rhs, false, expr.span)
} }
Operator::NotRegexMatch => { Operator::NotRegexMatch => {
let rhs = eval_expression(engine_state, stack, rhs)?; let rhs = eval_expression(engine_state, stack, rhs)?;
lhs.regex_match(op_span, &rhs, true) lhs.regex_match(op_span, &rhs, true, expr.span)
} }
Operator::Modulo => { Operator::Modulo => {
let rhs = eval_expression(engine_state, stack, rhs)?; let rhs = eval_expression(engine_state, stack, rhs)?;
lhs.modulo(op_span, &rhs) lhs.modulo(op_span, &rhs, expr.span)
} }
Operator::Pow => { Operator::Pow => {
let rhs = eval_expression(engine_state, stack, rhs)?; let rhs = eval_expression(engine_state, stack, rhs)?;
lhs.pow(op_span, &rhs) lhs.pow(op_span, &rhs, expr.span)
} }
Operator::StartsWith => { Operator::StartsWith => {
let rhs = eval_expression(engine_state, stack, rhs)?; let rhs = eval_expression(engine_state, stack, rhs)?;
lhs.starts_with(op_span, &rhs) lhs.starts_with(op_span, &rhs, expr.span)
} }
} }
} }

View File

@ -150,7 +150,7 @@ pub fn flatten_expression(
} }
for named in call.named_iter() { for named in call.named_iter() {
args.push((named.0.span, FlatShape::Flag)); args.push((named.0.span, FlatShape::Flag));
if let Some(expr) = &named.1 { if let Some(expr) = &named.2 {
args.extend(flatten_expression(working_set, expr)); args.extend(flatten_expression(working_set, expr));
} }
} }

View File

@ -51,8 +51,11 @@ impl Command for KnownExternal {
let extern_name = working_state.get_span_contents(call.head); let extern_name = working_state.get_span_contents(call.head);
let extern_name = String::from_utf8(extern_name.to_vec()) let extern_name = String::from_utf8(extern_name.to_vec())
.expect("this was already parsed as a command name"); .expect("this was already parsed as a command name");
let extern_name: Vec<_> = extern_name.split(' ').collect();
let arg_extern_name = Expression { let arg_extern_name = Expression {
expr: Expr::String(extern_name), expr: Expr::String(extern_name[0].to_string()),
span: call.head, span: call.head,
ty: Type::String, ty: Type::String,
custom_completion: None, custom_completion: None,
@ -60,10 +63,38 @@ impl Command for KnownExternal {
extern_call.add_positional(arg_extern_name); extern_call.add_positional(arg_extern_name);
for subcommand in extern_name.into_iter().skip(1) {
extern_call.add_positional(Expression {
expr: Expr::String(subcommand.to_string()),
span: call.head,
ty: Type::String,
custom_completion: None,
});
}
for arg in &call.arguments { for arg in &call.arguments {
match arg { match arg {
Argument::Positional(positional) => extern_call.add_positional(positional.clone()), Argument::Positional(positional) => extern_call.add_positional(positional.clone()),
Argument::Named(named) => extern_call.add_named(named.clone()), Argument::Named(named) => {
if let Some(short) = &named.1 {
extern_call.add_positional(Expression {
expr: Expr::String(format!("-{}", short.item)),
span: named.0.span,
ty: Type::String,
custom_completion: None,
});
} else {
extern_call.add_positional(Expression {
expr: Expr::String(format!("--{}", named.0.item)),
span: named.0.span,
ty: Type::String,
custom_completion: None,
});
}
if let Some(arg) = &named.2 {
extern_call.add_positional(arg.clone());
}
}
} }
} }
@ -74,6 +105,7 @@ impl Command for KnownExternal {
span: call_span, span: call_span,
}, },
None, None,
None,
)) ))
} }
@ -84,6 +116,7 @@ impl Command for KnownExternal {
span: call_span, span: call_span,
}, },
None, None,
None,
)) ))
} }

View File

@ -128,7 +128,7 @@ pub fn trim_quotes(bytes: &[u8]) -> &[u8] {
pub fn check_call(command: Span, sig: &Signature, call: &Call) -> Option<ParseError> { pub fn check_call(command: Span, sig: &Signature, call: &Call) -> Option<ParseError> {
// Allow the call to pass if they pass in the help flag // Allow the call to pass if they pass in the help flag
if call.named_iter().any(|(n, _)| n.item == "help") { if call.named_iter().any(|(n, _, _)| n.item == "help") {
return None; return None;
} }
@ -189,7 +189,7 @@ pub fn check_call(command: Span, sig: &Signature, call: &Call) -> Option<ParseEr
} }
} else { } else {
for req_flag in sig.named.iter().filter(|x| x.required) { for req_flag in sig.named.iter().filter(|x| x.required) {
if call.named_iter().all(|(n, _)| n.item != req_flag.long) { if call.named_iter().all(|(n, _, _)| n.item != req_flag.long) {
return Some(ParseError::MissingRequiredFlag( return Some(ParseError::MissingRequiredFlag(
req_flag.long.clone(), req_flag.long.clone(),
command, command,
@ -744,7 +744,7 @@ pub fn parse_internal_call(
if let Some(long_name) = long_name { if let Some(long_name) = long_name {
// We found a long flag, like --bar // We found a long flag, like --bar
error = error.or(err); error = error.or(err);
call.add_named((long_name, arg)); call.add_named((long_name, None, arg));
spans_idx += 1; spans_idx += 1;
continue; continue;
} }
@ -767,13 +767,30 @@ pub fn parse_internal_call(
parse_value(working_set, *arg, &arg_shape, expand_aliases_denylist); parse_value(working_set, *arg, &arg_shape, expand_aliases_denylist);
error = error.or(err); error = error.or(err);
if flag.long.is_empty() {
if let Some(short) = flag.short {
call.add_named((
Spanned {
item: String::new(),
span: spans[spans_idx],
},
Some(Spanned {
item: short.to_string(),
span: spans[spans_idx],
}),
Some(arg),
));
}
} else {
call.add_named(( call.add_named((
Spanned { Spanned {
item: flag.long.clone(), item: flag.long.clone(),
span: spans[spans_idx], span: spans[spans_idx],
}, },
None,
Some(arg), Some(arg),
)); ));
}
spans_idx += 1; spans_idx += 1;
} else { } else {
error = error.or_else(|| { error = error.or_else(|| {
@ -783,6 +800,20 @@ pub fn parse_internal_call(
)) ))
}) })
} }
} else if flag.long.is_empty() {
if let Some(short) = flag.short {
call.add_named((
Spanned {
item: String::new(),
span: spans[spans_idx],
},
Some(Spanned {
item: short.to_string(),
span: spans[spans_idx],
}),
None,
));
}
} else { } else {
call.add_named(( call.add_named((
Spanned { Spanned {
@ -790,6 +821,7 @@ pub fn parse_internal_call(
span: spans[spans_idx], span: spans[spans_idx],
}, },
None, None,
None,
)); ));
} }
} }
@ -4811,7 +4843,7 @@ pub fn discover_captures_in_expr(
} }
for named in call.named_iter() { for named in call.named_iter() {
if let Some(arg) = &named.1 { if let Some(arg) = &named.2 {
let result = discover_captures_in_expr(working_set, arg, seen, seen_blocks); let result = discover_captures_in_expr(working_set, arg, seen, seen_blocks);
output.extend(&result); output.extend(&result);
} }

View File

@ -29,7 +29,7 @@ impl EvaluatedCall {
.collect::<Result<Vec<Value>, ShellError>>()?; .collect::<Result<Vec<Value>, ShellError>>()?;
let mut named = Vec::with_capacity(call.named_len()); let mut named = Vec::with_capacity(call.named_len());
for (string, expr) in call.named_iter() { for (string, _, expr) in call.named_iter() {
let value = match expr { let value = match expr {
None => None, None => None,
Some(expr) => Some(eval_expression(engine_state, stack, expr)?), Some(expr) => Some(eval_expression(engine_state, stack, expr)?),

View File

@ -6,7 +6,7 @@ use crate::{DeclId, Span, Spanned};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Argument { pub enum Argument {
Positional(Expression), Positional(Expression),
Named((Spanned<String>, Option<Expression>)), Named((Spanned<String>, Option<Spanned<String>>, Option<Expression>)),
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
@ -30,7 +30,9 @@ impl Call {
} }
} }
pub fn named_iter(&self) -> impl Iterator<Item = &(Spanned<String>, Option<Expression>)> { pub fn named_iter(
&self,
) -> impl Iterator<Item = &(Spanned<String>, Option<Spanned<String>>, Option<Expression>)> {
self.arguments.iter().filter_map(|arg| match arg { self.arguments.iter().filter_map(|arg| match arg {
Argument::Named(named) => Some(named), Argument::Named(named) => Some(named),
Argument::Positional(_) => None, Argument::Positional(_) => None,
@ -39,7 +41,8 @@ impl Call {
pub fn named_iter_mut( pub fn named_iter_mut(
&mut self, &mut self,
) -> impl Iterator<Item = &mut (Spanned<String>, Option<Expression>)> { ) -> impl Iterator<Item = &mut (Spanned<String>, Option<Spanned<String>>, Option<Expression>)>
{
self.arguments.iter_mut().filter_map(|arg| match arg { self.arguments.iter_mut().filter_map(|arg| match arg {
Argument::Named(named) => Some(named), Argument::Named(named) => Some(named),
Argument::Positional(_) => None, Argument::Positional(_) => None,
@ -50,7 +53,10 @@ impl Call {
self.named_iter().count() self.named_iter().count()
} }
pub fn add_named(&mut self, named: (Spanned<String>, Option<Expression>)) { pub fn add_named(
&mut self,
named: (Spanned<String>, Option<Spanned<String>>, Option<Expression>),
) {
self.arguments.push(Argument::Named(named)); self.arguments.push(Argument::Named(named));
} }
@ -93,7 +99,7 @@ impl Call {
pub fn get_flag_expr(&self, flag_name: &str) -> Option<Expression> { pub fn get_flag_expr(&self, flag_name: &str) -> Option<Expression> {
for name in self.named_iter() { for name in self.named_iter() {
if flag_name == name.0.item { if flag_name == name.0.item {
return name.1.clone(); return name.2.clone();
} }
} }
@ -119,7 +125,7 @@ impl Call {
} }
} }
for (named, val) in self.named_iter() { for (named, _, val) in self.named_iter() {
if named.span.end > span.end { if named.span.end > span.end {
span.end = named.span.end; span.end = named.span.end;
} }

View File

@ -139,7 +139,7 @@ impl Expression {
} }
} }
for named in call.named_iter() { for named in call.named_iter() {
if let Some(expr) = &named.1 { if let Some(expr) = &named.2 {
if expr.has_in_variable(working_set) { if expr.has_in_variable(working_set) {
return true; return true;
} }
@ -306,7 +306,7 @@ impl Expression {
positional.replace_in_variable(working_set, new_var_id); positional.replace_in_variable(working_set, new_var_id);
} }
for named in call.named_iter_mut() { for named in call.named_iter_mut() {
if let Some(expr) = &mut named.1 { if let Some(expr) = &mut named.2 {
expr.replace_in_variable(working_set, new_var_id) expr.replace_in_variable(working_set, new_var_id)
} }
} }
@ -453,7 +453,7 @@ impl Expression {
positional.replace_span(working_set, replaced, new_span); positional.replace_span(working_set, replaced, new_span);
} }
for named in call.named_iter_mut() { for named in call.named_iter_mut() {
if let Some(expr) = &mut named.1 { if let Some(expr) = &mut named.2 {
expr.replace_span(working_set, replaced, new_span) expr.replace_span(working_set, replaced, new_span)
} }
} }

View File

@ -23,7 +23,7 @@ use std::path::PathBuf;
use std::{cmp::Ordering, fmt::Debug}; use std::{cmp::Ordering, fmt::Debug};
use crate::ast::{CellPath, PathMember}; use crate::ast::{CellPath, PathMember};
use crate::{did_you_mean, span, BlockId, Config, Span, Spanned, Type, VarId}; use crate::{did_you_mean, BlockId, Config, Span, Spanned, Type, VarId};
use crate::ast::Operator; use crate::ast::Operator;
pub use custom_value::CustomValue; pub use custom_value::CustomValue;
@ -1413,9 +1413,7 @@ impl PartialEq for Value {
} }
impl Value { impl Value {
pub fn add(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> { pub fn add(&self, op: Span, rhs: &Value, span: Span) -> Result<Value, ShellError> {
let span = span(&[self.span()?, rhs.span()?]);
match (self, rhs) { match (self, rhs) {
(Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => { (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => {
if let Some(val) = lhs.checked_add(*rhs) { if let Some(val) = lhs.checked_add(*rhs) {
@ -1486,9 +1484,7 @@ impl Value {
}), }),
} }
} }
pub fn sub(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> { pub fn sub(&self, op: Span, rhs: &Value, span: Span) -> Result<Value, ShellError> {
let span = span(&[self.span()?, rhs.span()?]);
match (self, rhs) { match (self, rhs) {
(Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => { (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => {
if let Some(val) = lhs.checked_sub(*rhs) { if let Some(val) = lhs.checked_sub(*rhs) {
@ -1566,9 +1562,7 @@ impl Value {
}), }),
} }
} }
pub fn mul(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> { pub fn mul(&self, op: Span, rhs: &Value, span: Span) -> Result<Value, ShellError> {
let span = span(&[self.span()?, rhs.span()?]);
match (self, rhs) { match (self, rhs) {
(Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => { (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => {
if let Some(val) = lhs.checked_mul(*rhs) { if let Some(val) = lhs.checked_mul(*rhs) {
@ -1629,9 +1623,7 @@ impl Value {
}), }),
} }
} }
pub fn div(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> { pub fn div(&self, op: Span, rhs: &Value, span: Span) -> Result<Value, ShellError> {
let span = span(&[self.span()?, rhs.span()?]);
match (self, rhs) { match (self, rhs) {
(Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => { (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => {
if *rhs != 0 { if *rhs != 0 {
@ -1747,9 +1739,7 @@ impl Value {
}), }),
} }
} }
pub fn lt(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> { pub fn lt(&self, op: Span, rhs: &Value, span: Span) -> Result<Value, ShellError> {
let span = span(&[self.span()?, rhs.span()?]);
if let (Value::CustomValue { val: lhs, span }, rhs) = (self, rhs) { if let (Value::CustomValue { val: lhs, span }, rhs) = (self, rhs) {
return lhs.operation(*span, Operator::LessThan, op, rhs); return lhs.operation(*span, Operator::LessThan, op, rhs);
} }
@ -1775,9 +1765,7 @@ impl Value {
}), }),
} }
} }
pub fn lte(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> { pub fn lte(&self, op: Span, rhs: &Value, span: Span) -> Result<Value, ShellError> {
let span = span(&[self.span()?, rhs.span()?]);
if let (Value::CustomValue { val: lhs, span }, rhs) = (self, rhs) { if let (Value::CustomValue { val: lhs, span }, rhs) = (self, rhs) {
return lhs.operation(*span, Operator::LessThanOrEqual, op, rhs); return lhs.operation(*span, Operator::LessThanOrEqual, op, rhs);
} }
@ -1803,9 +1791,7 @@ impl Value {
}), }),
} }
} }
pub fn gt(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> { pub fn gt(&self, op: Span, rhs: &Value, span: Span) -> Result<Value, ShellError> {
let span = span(&[self.span()?, rhs.span()?]);
if let (Value::CustomValue { val: lhs, span }, rhs) = (self, rhs) { if let (Value::CustomValue { val: lhs, span }, rhs) = (self, rhs) {
return lhs.operation(*span, Operator::GreaterThan, op, rhs); return lhs.operation(*span, Operator::GreaterThan, op, rhs);
} }
@ -1831,9 +1817,7 @@ impl Value {
}), }),
} }
} }
pub fn gte(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> { pub fn gte(&self, op: Span, rhs: &Value, span: Span) -> Result<Value, ShellError> {
let span = span(&[self.span()?, rhs.span()?]);
if let (Value::CustomValue { val: lhs, span }, rhs) = (self, rhs) { if let (Value::CustomValue { val: lhs, span }, rhs) = (self, rhs) {
return lhs.operation(*span, Operator::GreaterThanOrEqual, op, rhs); return lhs.operation(*span, Operator::GreaterThanOrEqual, op, rhs);
} }
@ -1859,9 +1843,7 @@ impl Value {
}), }),
} }
} }
pub fn eq(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> { pub fn eq(&self, op: Span, rhs: &Value, span: Span) -> Result<Value, ShellError> {
let span = span(&[self.span()?, rhs.span()?]);
if let (Value::CustomValue { val: lhs, span }, rhs) = (self, rhs) { if let (Value::CustomValue { val: lhs, span }, rhs) = (self, rhs) {
return lhs.operation(*span, Operator::Equal, op, rhs); return lhs.operation(*span, Operator::Equal, op, rhs);
} }
@ -1885,9 +1867,7 @@ impl Value {
}, },
} }
} }
pub fn ne(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> { pub fn ne(&self, op: Span, rhs: &Value, span: Span) -> Result<Value, ShellError> {
let span = span(&[self.span()?, rhs.span()?]);
if let (Value::CustomValue { val: lhs, span }, rhs) = (self, rhs) { if let (Value::CustomValue { val: lhs, span }, rhs) = (self, rhs) {
return lhs.operation(*span, Operator::NotEqual, op, rhs); return lhs.operation(*span, Operator::NotEqual, op, rhs);
} }
@ -1912,9 +1892,7 @@ impl Value {
} }
} }
pub fn r#in(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> { pub fn r#in(&self, op: Span, rhs: &Value, span: Span) -> Result<Value, ShellError> {
let span = span(&[self.span()?, rhs.span()?]);
match (self, rhs) { match (self, rhs) {
(lhs, Value::Range { val: rhs, .. }) => Ok(Value::Bool { (lhs, Value::Range { val: rhs, .. }) => Ok(Value::Bool {
val: rhs.contains(lhs), val: rhs.contains(lhs),
@ -1971,9 +1949,7 @@ impl Value {
} }
} }
pub fn not_in(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> { pub fn not_in(&self, op: Span, rhs: &Value, span: Span) -> Result<Value, ShellError> {
let span = span(&[self.span()?, rhs.span()?]);
match (self, rhs) { match (self, rhs) {
(lhs, Value::Range { val: rhs, .. }) => Ok(Value::Bool { (lhs, Value::Range { val: rhs, .. }) => Ok(Value::Bool {
val: !rhs.contains(lhs), val: !rhs.contains(lhs),
@ -2030,9 +2006,13 @@ impl Value {
} }
} }
pub fn regex_match(&self, op: Span, rhs: &Value, invert: bool) -> Result<Value, ShellError> { pub fn regex_match(
let span = span(&[self.span()?, rhs.span()?]); &self,
op: Span,
rhs: &Value,
invert: bool,
span: Span,
) -> Result<Value, ShellError> {
match (self, rhs) { match (self, rhs) {
( (
Value::String { val: lhs, .. }, Value::String { val: lhs, .. },
@ -2072,9 +2052,7 @@ impl Value {
} }
} }
pub fn starts_with(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> { pub fn starts_with(&self, op: Span, rhs: &Value, span: Span) -> Result<Value, ShellError> {
let span = span(&[self.span()?, rhs.span()?]);
match (self, rhs) { match (self, rhs) {
(Value::String { val: lhs, .. }, Value::String { val: rhs, .. }) => Ok(Value::Bool { (Value::String { val: lhs, .. }, Value::String { val: rhs, .. }) => Ok(Value::Bool {
val: lhs.starts_with(rhs), val: lhs.starts_with(rhs),
@ -2093,9 +2071,7 @@ impl Value {
} }
} }
pub fn modulo(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> { pub fn modulo(&self, op: Span, rhs: &Value, span: Span) -> Result<Value, ShellError> {
let span = span(&[self.span()?, rhs.span()?]);
match (self, rhs) { match (self, rhs) {
(Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => { (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => {
if *rhs != 0 { if *rhs != 0 {
@ -2151,9 +2127,7 @@ impl Value {
} }
} }
pub fn and(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> { pub fn and(&self, op: Span, rhs: &Value, span: Span) -> Result<Value, ShellError> {
let span = span(&[self.span()?, rhs.span()?]);
match (self, rhs) { match (self, rhs) {
(Value::Bool { val: lhs, .. }, Value::Bool { val: rhs, .. }) => Ok(Value::Bool { (Value::Bool { val: lhs, .. }, Value::Bool { val: rhs, .. }) => Ok(Value::Bool {
val: *lhs && *rhs, val: *lhs && *rhs,
@ -2172,9 +2146,7 @@ impl Value {
} }
} }
pub fn or(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> { pub fn or(&self, op: Span, rhs: &Value, span: Span) -> Result<Value, ShellError> {
let span = span(&[self.span()?, rhs.span()?]);
match (self, rhs) { match (self, rhs) {
(Value::Bool { val: lhs, .. }, Value::Bool { val: rhs, .. }) => Ok(Value::Bool { (Value::Bool { val: lhs, .. }, Value::Bool { val: rhs, .. }) => Ok(Value::Bool {
val: *lhs || *rhs, val: *lhs || *rhs,
@ -2193,9 +2165,7 @@ impl Value {
} }
} }
pub fn pow(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> { pub fn pow(&self, op: Span, rhs: &Value, span: Span) -> Result<Value, ShellError> {
let span = span(&[self.span()?, rhs.span()?]);
match (self, rhs) { match (self, rhs) {
(Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => { (Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => {
if let Some(val) = lhs.checked_pow(*rhs as u32) { if let Some(val) = lhs.checked_pow(*rhs as u32) {

View File

@ -38,7 +38,7 @@ impl Range {
}; };
let to = if let Value::Nothing { .. } = to { let to = if let Value::Nothing { .. } = to {
if let Ok(Value::Bool { val: true, .. }) = next.lt(expr_span, &from) { if let Ok(Value::Bool { val: true, .. }) = next.lt(expr_span, &from, expr_span) {
Value::Int { Value::Int {
val: i64::MIN, val: i64::MIN,
span: expr_span, span: expr_span,
@ -54,7 +54,10 @@ impl Range {
}; };
// Check if the range counts up or down // Check if the range counts up or down
let moves_up = matches!(from.lte(expr_span, &to), Ok(Value::Bool { val: true, .. })); let moves_up = matches!(
from.lte(expr_span, &to, expr_span),
Ok(Value::Bool { val: true, .. })
);
// Convert the next value into the inctement // Convert the next value into the inctement
let incr = if let Value::Nothing { .. } = next { let incr = if let Value::Nothing { .. } = next {
@ -70,7 +73,7 @@ impl Range {
} }
} }
} else { } else {
next.sub(operator.next_op_span, &from)? next.sub(operator.next_op_span, &from, expr_span)?
}; };
let zero = Value::Int { let zero = Value::Int {
@ -79,22 +82,25 @@ impl Range {
}; };
// Increment must be non-zero, otherwise we iterate forever // Increment must be non-zero, otherwise we iterate forever
if matches!(incr.eq(expr_span, &zero), Ok(Value::Bool { val: true, .. })) { if matches!(
incr.eq(expr_span, &zero, expr_span),
Ok(Value::Bool { val: true, .. })
) {
return Err(ShellError::CannotCreateRange(expr_span)); return Err(ShellError::CannotCreateRange(expr_span));
} }
// If to > from, then incr > 0, otherwise we iterate forever // If to > from, then incr > 0, otherwise we iterate forever
if let (Value::Bool { val: true, .. }, Value::Bool { val: false, .. }) = ( if let (Value::Bool { val: true, .. }, Value::Bool { val: false, .. }) = (
to.gt(operator.span, &from)?, to.gt(operator.span, &from, expr_span)?,
incr.gt(operator.next_op_span, &zero)?, incr.gt(operator.next_op_span, &zero, expr_span)?,
) { ) {
return Err(ShellError::CannotCreateRange(expr_span)); return Err(ShellError::CannotCreateRange(expr_span));
} }
// If to < from, then incr < 0, otherwise we iterate forever // If to < from, then incr < 0, otherwise we iterate forever
if let (Value::Bool { val: true, .. }, Value::Bool { val: false, .. }) = ( if let (Value::Bool { val: true, .. }, Value::Bool { val: false, .. }) = (
to.lt(operator.span, &from)?, to.lt(operator.span, &from, expr_span)?,
incr.lt(operator.next_op_span, &zero)?, incr.lt(operator.next_op_span, &zero, expr_span)?,
) { ) {
return Err(ShellError::CannotCreateRange(expr_span)); return Err(ShellError::CannotCreateRange(expr_span));
} }
@ -231,7 +237,7 @@ impl Iterator for RangeIterator {
if (ordering == desired_ordering) || (self.is_end_inclusive && ordering == Ordering::Equal) if (ordering == desired_ordering) || (self.is_end_inclusive && ordering == Ordering::Equal)
{ {
let next_value = self.curr.add(self.span, &self.incr); let next_value = self.curr.add(self.span, &self.incr, self.span);
let mut next = match next_value { let mut next = match next_value {
Ok(result) => result, Ok(result) => result,

View File

@ -23,22 +23,22 @@ fn test_comparison_nothing() {
for value in values { for value in values {
assert!(matches!( assert!(matches!(
value.eq(Span::test_data(), &nothing), value.eq(Span::test_data(), &nothing, Span::test_data()),
Ok(Value::Bool { val: false, .. }) Ok(Value::Bool { val: false, .. })
)); ));
assert!(matches!( assert!(matches!(
value.ne(Span::test_data(), &nothing), value.ne(Span::test_data(), &nothing, Span::test_data()),
Ok(Value::Bool { val: true, .. }) Ok(Value::Bool { val: true, .. })
)); ));
assert!(matches!( assert!(matches!(
nothing.eq(Span::test_data(), &value), nothing.eq(Span::test_data(), &value, Span::test_data()),
Ok(Value::Bool { val: false, .. }) Ok(Value::Bool { val: false, .. })
)); ));
assert!(matches!( assert!(matches!(
nothing.ne(Span::test_data(), &value), nothing.ne(Span::test_data(), &value, Span::test_data()),
Ok(Value::Bool { val: true, .. }) Ok(Value::Bool { val: true, .. })
)); ));
} }

View File

@ -366,3 +366,11 @@ fn reuseable_in() -> TestResult {
"6", "6",
) )
} }
#[test]
fn better_operator_spans() -> TestResult {
run_test(
r#"metadata ({foo: 10} | (20 - $in.foo)) | get span | $in.start < $in.end"#,
"true",
)
}