From 8f9dd6516e1ac090857348d976a63d5a9cf47f6c Mon Sep 17 00:00:00 2001 From: Belhorma Bendebiche Date: Thu, 21 Nov 2019 12:18:00 -0500 Subject: [PATCH] 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. --- crates/nu-parser/src/debug.rs | 51 ----------------------------- crates/nu-parser/src/hir.rs | 6 ---- crates/nu-parser/src/lib.rs | 1 - crates/nu-source/src/lib.rs | 1 + src/commands/classified/dynamic.rs | 2 +- src/commands/classified/external.rs | 10 +++--- src/commands/classified/internal.rs | 11 ++++--- src/commands/classified/mod.rs | 5 ++- src/commands/nth.rs | 2 +- src/data/base.rs | 6 ++-- src/data/value.rs | 4 +-- src/evaluate/evaluator.rs | 6 ---- src/evaluate/operator.rs | 16 ++++----- 13 files changed, 30 insertions(+), 91 deletions(-) delete mode 100644 crates/nu-parser/src/debug.rs diff --git a/crates/nu-parser/src/debug.rs b/crates/nu-parser/src/debug.rs deleted file mode 100644 index cf6770c6f9..0000000000 --- a/crates/nu-parser/src/debug.rs +++ /dev/null @@ -1,51 +0,0 @@ -use nu_source::ShellAnnotation; -use pretty::{Render, RenderAnnotated}; -use std::io; -use termcolor::WriteColor; - -pub struct TermColored<'a, W> { - color_stack: Vec, - upstream: &'a mut W, -} - -impl<'a, W> TermColored<'a, W> { - pub fn new(upstream: &'a mut W) -> TermColored<'a, W> { - TermColored { - color_stack: Vec::new(), - upstream, - } - } -} - -impl<'a, W> Render for TermColored<'a, W> -where - W: io::Write, -{ - type Error = io::Error; - - fn write_str(&mut self, s: &str) -> io::Result { - self.upstream.write(s.as_bytes()) - } - - fn write_str_all(&mut self, s: &str) -> io::Result<()> { - self.upstream.write_all(s.as_bytes()) - } -} - -impl<'a, W> RenderAnnotated for TermColored<'a, W> -where - W: WriteColor, -{ - fn push_annotation(&mut self, ann: &ShellAnnotation) -> Result<(), Self::Error> { - self.color_stack.push(*ann); - self.upstream.set_color(&(*ann).into()) - } - - fn pop_annotation(&mut self) -> Result<(), Self::Error> { - self.color_stack.pop(); - match self.color_stack.last() { - Some(previous) => self.upstream.set_color(&(*previous).into()), - None => self.upstream.reset(), - } - } -} diff --git a/crates/nu-parser/src/hir.rs b/crates/nu-parser/src/hir.rs index b4c15e2905..42e01e2d6a 100644 --- a/crates/nu-parser/src/hir.rs +++ b/crates/nu-parser/src/hir.rs @@ -13,13 +13,7 @@ use crate::parse::parser::Number; use crate::parse::unit::Unit; use derive_new::new; use getset::Getters; -#[cfg(not(coloring_in_tokens))] -use nu_errors::ShellError; -#[cfg(not(coloring_in_tokens))] -use nu_protocol::{EvaluatedArgs, Scope}; use nu_protocol::{PathMember, ShellTypeName}; -#[cfg(not(coloring_in_tokens))] -use nu_source::Text; use nu_source::{ b, DebugDocBuilder, HasSpan, PrettyDebug, PrettyDebugWithSource, Span, Spanned, SpannedItem, }; diff --git a/crates/nu-parser/src/lib.rs b/crates/nu-parser/src/lib.rs index e80df9b261..41c7cde5f5 100644 --- a/crates/nu-parser/src/lib.rs +++ b/crates/nu-parser/src/lib.rs @@ -1,5 +1,4 @@ pub mod commands; -pub mod debug; pub mod hir; pub mod parse; pub mod parse_command; diff --git a/crates/nu-source/src/lib.rs b/crates/nu-source/src/lib.rs index 840ba6a750..524e53b8c7 100644 --- a/crates/nu-source/src/lib.rs +++ b/crates/nu-source/src/lib.rs @@ -11,5 +11,6 @@ pub use self::meta::{ pub use self::pretty::{ b, DebugDoc, DebugDocBuilder, PrettyDebug, PrettyDebugWithSource, ShellAnnotation, }; +pub use self::term_colored::TermColored; pub use self::text::Text; pub use self::tracable::{nom_input, NomSpan, TracableContext}; diff --git a/src/commands/classified/dynamic.rs b/src/commands/classified/dynamic.rs index 8e6e7d6510..31194f6b61 100644 --- a/src/commands/classified/dynamic.rs +++ b/src/commands/classified/dynamic.rs @@ -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 { diff --git a/src/commands/classified/external.rs b/src/commands/classified/external.rs index f668abad12..e5d8d04924 100644 --- a/src/commands/classified/external.rs +++ b/src/commands/classified/external.rs @@ -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> )) diff --git a/src/commands/classified/internal.rs b/src/commands/classified/internal.rs index 582f7d7986..09aa0ff06a 100644 --- a/src/commands/classified/internal.rs +++ b/src/commands/classified/internal.rs @@ -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) => { diff --git a/src/commands/classified/mod.rs b/src/commands/classified/mod.rs index b3add6eccb..2d1ea10b4e 100644 --- a/src/commands/classified/mod.rs +++ b/src/commands/classified/mod.rs @@ -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, } } diff --git a/src/commands/nth.rs b/src/commands/nth.rs index e740960fec..94e0e0005c 100644 --- a/src/commands/nth.rs +++ b/src/commands/nth.rs @@ -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)] diff --git a/src/data/base.rs b/src/data/base.rs index 70549b48e0..54341467f7 100644 --- a/src/data/base.rs +++ b/src/data/base.rs @@ -150,10 +150,10 @@ impl CompareValues { } pub(crate) fn coerce_compare( - left: &Value, - right: &Value, + left: &UntaggedValue, + right: &UntaggedValue, ) -> Result { - match (&left.value, &right.value) { + match (left, right) { (UntaggedValue::Primitive(left), UntaggedValue::Primitive(right)) => { coerce_compare_primitive(left, right) } diff --git a/src/data/value.rs b/src/data/value.rs index 17d78c4597..5088c6621b 100644 --- a/src/data/value.rs +++ b/src/data/value.rs @@ -98,8 +98,8 @@ pub fn nothing() -> UntaggedValue { pub fn compare_values( operator: &Operator, - left: &Value, - right: &Value, + left: &UntaggedValue, + right: &UntaggedValue, ) -> Result { match operator { _ => { diff --git a/src/evaluate/evaluator.rs b/src/evaluate/evaluator.rs index 19d87ea308..4a3d3a1ccb 100644 --- a/src/evaluate/evaluator.rs +++ b/src/evaluate/evaluator.rs @@ -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; diff --git a/src/evaluate/operator.rs b/src/evaluate/operator.rs index ba450a5137..b9981615db 100644 --- a/src/evaluate/operator.rs +++ b/src/evaluate/operator.rs @@ -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), } }