Add =~ and !~ operators on strings

`left =~ right` return true if left contains right, using Rust's
`String::contains`. `!~` is the negated version.

A new `apply_operator` function is added which decouples evaluation from
`Value::compare`. This returns a `Value` and opens the door to
implementing `+` for example, though it wouldn't be useful immediately.

The `operator!` macro had to be changed slightly as it would choke on
`~` in arguments.
This commit is contained in:
Belhorma Bendebiche
2019-11-21 12:18:00 -05:00
committed by Yehuda Katz
parent e4226def16
commit 8f9dd6516e
13 changed files with 30 additions and 91 deletions

View File

@ -1,5 +1,5 @@
use crate::parser::hir;
use derive_new::new;
use nu_parser::hir;
#[derive(new, Debug, Eq, PartialEq)]
pub(crate) struct Command {

View File

@ -1,9 +1,12 @@
use super::ClassifiedInputStream;
use crate::data::value;
use crate::prelude::*;
use bytes::{BufMut, BytesMut};
use futures::stream::StreamExt;
use futures_codec::{Decoder, Encoder, Framed};
use log::trace;
use nu_errors::ShellError;
use nu_protocol::Value;
use std::io::{Error, ErrorKind};
use subprocess::Exec;
@ -105,7 +108,7 @@ impl Command {
let input_strings = inputs
.iter()
.map(|i| {
i.as_string().map_err(|_| {
i.as_string().map(|s| s.to_string()).map_err(|_| {
let arg = self.args.iter().find(|arg| arg.arg.contains("$it"));
if let Some(arg) = arg {
ShellError::labeled_error(
@ -206,9 +209,8 @@ impl Command {
let stdout = popen.stdout.take().unwrap();
let file = futures::io::AllowStdIo::new(stdout);
let stream = Framed::new(file, LinesCodec {});
let stream = stream.map(move |line| {
UntaggedValue::string(line.unwrap()).into_value(&name_tag)
});
let stream =
stream.map(move |line| value::string(line.unwrap()).into_value(&name_tag));
Ok(ClassifiedInputStream::from_input_stream(
stream.boxed() as BoxStream<'static, Value>
))

View File

@ -1,7 +1,10 @@
use crate::parser::hir;
use crate::data::value;
use crate::prelude::*;
use derive_new::new;
use log::{log_enabled, trace};
use nu_errors::ShellError;
use nu_parser::hir;
use nu_protocol::{CommandAction, Primitive, ReturnSuccess, UntaggedValue, Value};
use super::ClassifiedInputStream;
@ -77,7 +80,7 @@ impl Command {
} => {
context.shell_manager.insert_at_current(Box::new(
HelpShell::for_command(
UntaggedValue::string(cmd).into_value(tag),
value::string(cmd).into_value(tag),
&context.registry(),
).unwrap(),
));
@ -126,12 +129,12 @@ impl Command {
doc.render_raw(
context.with_host(|host| host.width() - 5),
&mut crate::parser::debug::TermColored::new(&mut buffer),
&mut nu_source::TermColored::new(&mut buffer),
).unwrap();
let value = String::from_utf8_lossy(buffer.as_slice());
yield Ok(UntaggedValue::string(value).into_untagged_value())
yield Ok(value::string(value).into_untagged_value())
}
Err(err) => {

View File

@ -1,5 +1,5 @@
use crate::parser::{hir, TokenNode};
use crate::prelude::*;
use nu_parser::{hir, TokenNode};
mod dynamic;
mod external;
@ -11,7 +11,6 @@ pub(crate) use dynamic::Command as DynamicCommand;
#[allow(unused_imports)]
pub(crate) use external::{Command as ExternalCommand, ExternalArg, ExternalArgs, StreamNext};
pub(crate) use internal::Command as InternalCommand;
pub(crate) use pipeline::Pipeline as ClassifiedPipeline;
pub(crate) struct ClassifiedInputStream {
pub(crate) objects: InputStream,
@ -21,7 +20,7 @@ pub(crate) struct ClassifiedInputStream {
impl ClassifiedInputStream {
pub(crate) fn new() -> ClassifiedInputStream {
ClassifiedInputStream {
objects: vec![UntaggedValue::nothing().into_untagged_value()].into(),
objects: vec![crate::data::value::nothing().into_untagged_value()].into(),
stdin: None,
}
}

View File

@ -1,8 +1,8 @@
use crate::commands::WholeStreamCommand;
use crate::context::CommandRegistry;
use crate::prelude::*;
use nu_protocol::{Signature, SyntaxShape};
use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape};
use nu_source::Tagged;
#[derive(Deserialize)]

View File

@ -150,10 +150,10 @@ impl CompareValues {
}
pub(crate) fn coerce_compare(
left: &Value,
right: &Value,
left: &UntaggedValue,
right: &UntaggedValue,
) -> Result<CompareValues, (&'static str, &'static str)> {
match (&left.value, &right.value) {
match (left, right) {
(UntaggedValue::Primitive(left), UntaggedValue::Primitive(right)) => {
coerce_compare_primitive(left, right)
}

View File

@ -98,8 +98,8 @@ pub fn nothing() -> UntaggedValue {
pub fn compare_values(
operator: &Operator,
left: &Value,
right: &Value,
left: &UntaggedValue,
right: &UntaggedValue,
) -> Result<bool, (&'static str, &'static str)> {
match operator {
_ => {

View File

@ -1,13 +1,7 @@
use crate::context::CommandRegistry;
use crate::data::base::Block;
use crate::data::value;
use crate::errors::ArgumentError;
use crate::evaluate::operator::apply_operator;
use crate::parser::hir::path::{ColumnPath, UnspannedPathMember};
use crate::parser::{
hir::{self, Expression, RawExpression},
CommandRegistry,
};
use crate::prelude::*;
use crate::TaggedDictBuilder;
use log::trace;

View File

@ -1,6 +1,6 @@
use crate::data::base::{Primitive, UntaggedValue, Value};
use crate::parser::Operator;
use crate::traits::ShellTypeName;
use crate::data::value;
use nu_parser::Operator;
use nu_protocol::{Primitive, ShellTypeName, UntaggedValue, Value};
use std::ops::Not;
pub fn apply_operator(
@ -14,12 +14,10 @@ pub fn apply_operator(
| Operator::LessThan
| Operator::GreaterThan
| Operator::LessThanOrEqual
| Operator::GreaterThanOrEqual => left.compare(op, right).map(UntaggedValue::boolean),
Operator::Dot => Ok(UntaggedValue::boolean(false)),
Operator::Contains => contains(left, right).map(UntaggedValue::boolean),
Operator::NotContains => contains(left, right)
.map(Not::not)
.map(UntaggedValue::boolean),
| Operator::GreaterThanOrEqual => left.compare(op, right).map(value::boolean),
Operator::Dot => Ok(value::boolean(false)),
Operator::Contains => contains(left, right).map(value::boolean),
Operator::NotContains => contains(left, right).map(Not::not).map(value::boolean),
}
}