mirror of
https://github.com/nushell/nushell.git
synced 2025-08-14 02:09:04 +02:00
Add Range and start Signature support
This commit contains two improvements: - Support for a Range syntax (and a corresponding Range value) - Work towards a signature syntax Implementing the Range syntax resulted in cleaning up how operators in the core syntax works. There are now two kinds of infix operators - tight operators (`.` and `..`) - loose operators Tight operators may not be interspersed (`$it.left..$it.right` is a syntax error). Loose operators require whitespace on both sides of the operator, and can be arbitrarily interspersed. Precedence is left to right in the core syntax. Note that delimited syntax (like `( ... )` or `[ ... ]`) is a single token node in the core syntax. A single token node can be parsed from beginning to end in a context-free manner. The rule for `.` is `<token node>.<member>`. The rule for `..` is `<token node>..<token node>`. Loose operators all have the same syntactic rule: `<token node><space><loose op><space><token node>`. The second aspect of this pull request is the beginning of support for a signature syntax. Before implementing signatures, a necessary prerequisite is for the core syntax to support multi-line programs. That work establishes a few things: - `;` and newlines are handled in the core grammar, and both count as "separators" - line comments begin with `#` and continue until the end of the line In this commit, multi-token productions in the core grammar can use separators interchangably with spaces. However, I think we will ultimately want a different rule preventing separators from occurring before an infix operator, so that the end of a line is always unambiguous. This would avoid gratuitous differences between modules and repl usage. We already effectively have this rule, because otherwise `x<newline> | y` would be a single pipeline, but of course that wouldn't work.
This commit is contained in:
@ -1,6 +1,7 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_macros::signature;
|
||||
use nu_protocol::{Signature, SyntaxShape};
|
||||
|
||||
pub struct CD;
|
||||
@ -11,11 +12,17 @@ impl WholeStreamCommand for CD {
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("cd").optional(
|
||||
"directory",
|
||||
SyntaxShape::Path,
|
||||
"the directory to change to",
|
||||
)
|
||||
signature! {
|
||||
def cd {
|
||||
"the directory to change to"
|
||||
directory(optional Path) - "the directory to change to"
|
||||
}
|
||||
}
|
||||
// Signature::build("cd").optional(
|
||||
// "directory",
|
||||
// SyntaxShape::Path,
|
||||
// "the directory to change to",
|
||||
// )
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
|
@ -378,14 +378,7 @@ pub trait WholeStreamCommand: Send + Sync {
|
||||
fn name(&self) -> &str;
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature {
|
||||
name: self.name().to_string(),
|
||||
usage: self.usage().to_string(),
|
||||
positional: vec![],
|
||||
rest_positional: None,
|
||||
named: indexmap::IndexMap::new(),
|
||||
is_filter: true,
|
||||
}
|
||||
Signature::new(self.name()).desc(self.usage()).filter()
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str;
|
||||
@ -405,14 +398,7 @@ pub trait PerItemCommand: Send + Sync {
|
||||
fn name(&self) -> &str;
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature {
|
||||
name: self.name().to_string(),
|
||||
usage: self.usage().to_string(),
|
||||
positional: vec![],
|
||||
rest_positional: None,
|
||||
named: indexmap::IndexMap::new(),
|
||||
is_filter: true,
|
||||
}
|
||||
Signature::new(self.name()).desc(self.usage()).filter()
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str;
|
||||
|
@ -1,5 +1,6 @@
|
||||
use crate::commands::WholeStreamCommand;
|
||||
use crate::context::CommandRegistry;
|
||||
use crate::deserializer::NumericRange;
|
||||
use crate::prelude::*;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::{Signature, SyntaxShape};
|
||||
@ -7,7 +8,7 @@ use nu_source::Tagged;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct RangeArgs {
|
||||
area: Tagged<String>,
|
||||
area: Tagged<NumericRange>,
|
||||
}
|
||||
|
||||
pub struct Range;
|
||||
@ -20,7 +21,7 @@ impl WholeStreamCommand for Range {
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build("range").required(
|
||||
"rows ",
|
||||
SyntaxShape::Any,
|
||||
SyntaxShape::Range,
|
||||
"range of rows to return: Eg) 4..7 (=> from 4 to 7)",
|
||||
)
|
||||
}
|
||||
@ -39,48 +40,14 @@ impl WholeStreamCommand for Range {
|
||||
}
|
||||
|
||||
fn range(
|
||||
RangeArgs { area: rows }: RangeArgs,
|
||||
RunnableContext { input, name, .. }: RunnableContext,
|
||||
RangeArgs { area }: RangeArgs,
|
||||
RunnableContext { input, name: _, .. }: RunnableContext,
|
||||
) -> Result<OutputStream, ShellError> {
|
||||
match rows.item.find('.') {
|
||||
Some(value) => {
|
||||
let (first, last) = rows.item.split_at(value);
|
||||
let first = match first.parse::<u64>() {
|
||||
Ok(postion) => postion,
|
||||
Err(_) => {
|
||||
if first == "" {
|
||||
0
|
||||
} else {
|
||||
return Err(ShellError::labeled_error(
|
||||
"no correct start of range",
|
||||
"'from' needs to be an Integer or empty",
|
||||
name,
|
||||
));
|
||||
}
|
||||
}
|
||||
};
|
||||
let last = match last.trim_start_matches('.').parse::<u64>() {
|
||||
Ok(postion) => postion,
|
||||
Err(_) => {
|
||||
if last == ".." {
|
||||
std::u64::MAX - 1
|
||||
} else {
|
||||
return Err(ShellError::labeled_error(
|
||||
"no correct end of range",
|
||||
"'to' needs to be an Integer or empty",
|
||||
name,
|
||||
));
|
||||
}
|
||||
}
|
||||
};
|
||||
Ok(OutputStream::from_input(
|
||||
input.values.skip(first).take(last - first + 1),
|
||||
))
|
||||
}
|
||||
None => Err(ShellError::labeled_error(
|
||||
"No correct formatted range found",
|
||||
"format: <from>..<to>",
|
||||
name,
|
||||
)),
|
||||
}
|
||||
let range = area.item;
|
||||
let (from, _) = range.from;
|
||||
let (to, _) = range.to;
|
||||
|
||||
return Ok(OutputStream::from_input(
|
||||
input.values.skip(*from).take(*to - *from + 1),
|
||||
));
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ pub fn value_to_bson_value(v: &Value) -> Result<Bson, ShellError> {
|
||||
.map(|x| value_to_bson_value(x))
|
||||
.collect::<Result<_, _>>()?,
|
||||
),
|
||||
UntaggedValue::Block(_) => Bson::Null,
|
||||
UntaggedValue::Block(_) | UntaggedValue::Primitive(Primitive::Range(_)) => Bson::Null,
|
||||
UntaggedValue::Error(e) => return Err(e.clone()),
|
||||
UntaggedValue::Primitive(Primitive::Binary(b)) => {
|
||||
Bson::Binary(BinarySubtype::Generic, b.clone())
|
||||
|
@ -76,7 +76,9 @@ pub fn value_to_json_value(v: &Value) -> Result<serde_json::Value, ShellError> {
|
||||
|
||||
UntaggedValue::Table(l) => serde_json::Value::Array(json_list(l)?),
|
||||
UntaggedValue::Error(e) => return Err(e.clone()),
|
||||
UntaggedValue::Block(_) => serde_json::Value::Null,
|
||||
UntaggedValue::Block(_) | UntaggedValue::Primitive(Primitive::Range(_)) => {
|
||||
serde_json::Value::Null
|
||||
}
|
||||
UntaggedValue::Primitive(Primitive::Binary(b)) => serde_json::Value::Array(
|
||||
b.iter()
|
||||
.map(|x| {
|
||||
|
@ -100,9 +100,10 @@ fn nu_value_to_sqlite_string(v: Value) -> String {
|
||||
Primitive::Date(d) => format!("'{}'", d),
|
||||
Primitive::Path(p) => format!("'{}'", p.display().to_string().replace("'", "''")),
|
||||
Primitive::Binary(u) => format!("x'{}'", encode(u)),
|
||||
Primitive::BeginningOfStream | Primitive::EndOfStream | Primitive::ColumnPath(_) => {
|
||||
"NULL".into()
|
||||
}
|
||||
Primitive::BeginningOfStream
|
||||
| Primitive::EndOfStream
|
||||
| Primitive::ColumnPath(_)
|
||||
| Primitive::Range(_) => "NULL".into(),
|
||||
},
|
||||
_ => "NULL".into(),
|
||||
}
|
||||
|
@ -69,6 +69,7 @@ pub fn value_to_toml_value(v: &Value) -> Result<toml::Value, ShellError> {
|
||||
UntaggedValue::Table(l) => toml::Value::Array(collect_values(l)?),
|
||||
UntaggedValue::Error(e) => return Err(e.clone()),
|
||||
UntaggedValue::Block(_) => toml::Value::String("<Block>".to_string()),
|
||||
UntaggedValue::Primitive(Primitive::Range(_)) => toml::Value::String("<Range>".to_string()),
|
||||
UntaggedValue::Primitive(Primitive::Binary(b)) => {
|
||||
toml::Value::Array(b.iter().map(|x| toml::Value::Integer(*x as i64)).collect())
|
||||
}
|
||||
|
@ -85,7 +85,9 @@ pub fn value_to_yaml_value(v: &Value) -> Result<serde_yaml::Value, ShellError> {
|
||||
serde_yaml::Value::Sequence(out)
|
||||
}
|
||||
UntaggedValue::Error(e) => return Err(e.clone()),
|
||||
UntaggedValue::Block(_) => serde_yaml::Value::Null,
|
||||
UntaggedValue::Block(_) | UntaggedValue::Primitive(Primitive::Range(_)) => {
|
||||
serde_yaml::Value::Null
|
||||
}
|
||||
UntaggedValue::Primitive(Primitive::Binary(b)) => serde_yaml::Value::Sequence(
|
||||
b.iter()
|
||||
.map(|x| serde_yaml::Value::Number(serde_yaml::Number::from(*x)))
|
||||
|
@ -7,7 +7,7 @@ use chrono::{DateTime, Utc};
|
||||
use derive_new::new;
|
||||
use log::trace;
|
||||
use nu_errors::ShellError;
|
||||
use nu_parser::{hir, Operator};
|
||||
use nu_parser::{hir, CompareOperator};
|
||||
use nu_protocol::{
|
||||
Evaluate, EvaluateTrait, Primitive, Scope, ShellTypeName, SpannedTypeName, TaggedDictBuilder,
|
||||
UntaggedValue, Value,
|
||||
@ -23,7 +23,7 @@ use std::time::SystemTime;
|
||||
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Clone, new, Serialize)]
|
||||
pub struct Operation {
|
||||
pub(crate) left: Value,
|
||||
pub(crate) operator: Operator,
|
||||
pub(crate) operator: CompareOperator,
|
||||
pub(crate) right: Value,
|
||||
}
|
||||
|
||||
|
@ -1,207 +1,24 @@
|
||||
use crate::prelude::*;
|
||||
use chrono::{DateTime, Utc};
|
||||
use chrono_humanize::Humanize;
|
||||
use derive_new::new;
|
||||
use indexmap::IndexMap;
|
||||
use nu_errors::ShellError;
|
||||
use nu_protocol::RangeInclusion;
|
||||
use nu_protocol::{
|
||||
format_primitive, ColumnPath, Dictionary, Evaluate, Primitive, ShellTypeName,
|
||||
TaggedDictBuilder, UntaggedValue, Value,
|
||||
};
|
||||
use nu_source::{b, DebugDoc, PrettyDebug};
|
||||
use nu_source::{b, PrettyDebug};
|
||||
use std::collections::BTreeMap;
|
||||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
|
||||
/**
|
||||
This file describes the structural types of the nushell system.
|
||||
|
||||
Its primary purpose today is to identify "equivalent" values for the purpose
|
||||
of merging rows into a single table or identify rows in a table that have the
|
||||
same shape for reflection.
|
||||
|
||||
It also serves as the primary vehicle for pretty-printing.
|
||||
*/
|
||||
|
||||
#[allow(unused)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
pub enum TypeShape {
|
||||
Nothing,
|
||||
Int,
|
||||
Decimal,
|
||||
Bytesize,
|
||||
String,
|
||||
Line,
|
||||
ColumnPath,
|
||||
Pattern,
|
||||
Boolean,
|
||||
Date,
|
||||
Duration,
|
||||
Path,
|
||||
Binary,
|
||||
|
||||
Row(BTreeMap<Column, TypeShape>),
|
||||
Table(Vec<TypeShape>),
|
||||
|
||||
// TODO: Block arguments
|
||||
Block,
|
||||
// TODO: Error type
|
||||
Error,
|
||||
|
||||
// Stream markers (used as bookend markers rather than actual values)
|
||||
BeginningOfStream,
|
||||
EndOfStream,
|
||||
}
|
||||
|
||||
impl TypeShape {
|
||||
pub fn from_primitive(primitive: &Primitive) -> TypeShape {
|
||||
match primitive {
|
||||
Primitive::Nothing => TypeShape::Nothing,
|
||||
Primitive::Int(_) => TypeShape::Int,
|
||||
Primitive::Decimal(_) => TypeShape::Decimal,
|
||||
Primitive::Bytes(_) => TypeShape::Bytesize,
|
||||
Primitive::String(_) => TypeShape::String,
|
||||
Primitive::Line(_) => TypeShape::Line,
|
||||
Primitive::ColumnPath(_) => TypeShape::ColumnPath,
|
||||
Primitive::Pattern(_) => TypeShape::Pattern,
|
||||
Primitive::Boolean(_) => TypeShape::Boolean,
|
||||
Primitive::Date(_) => TypeShape::Date,
|
||||
Primitive::Duration(_) => TypeShape::Duration,
|
||||
Primitive::Path(_) => TypeShape::Path,
|
||||
Primitive::Binary(_) => TypeShape::Binary,
|
||||
Primitive::BeginningOfStream => TypeShape::BeginningOfStream,
|
||||
Primitive::EndOfStream => TypeShape::EndOfStream,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_dictionary(dictionary: &Dictionary) -> TypeShape {
|
||||
let mut map = BTreeMap::new();
|
||||
|
||||
for (key, value) in dictionary.entries.iter() {
|
||||
let column = Column::String(key.clone());
|
||||
map.insert(column, TypeShape::from_value(value));
|
||||
}
|
||||
|
||||
TypeShape::Row(map)
|
||||
}
|
||||
|
||||
pub fn from_table<'a>(table: impl IntoIterator<Item = &'a Value>) -> TypeShape {
|
||||
let mut vec = vec![];
|
||||
|
||||
for item in table.into_iter() {
|
||||
vec.push(TypeShape::from_value(item))
|
||||
}
|
||||
|
||||
TypeShape::Table(vec)
|
||||
}
|
||||
|
||||
pub fn from_value<'a>(value: impl Into<&'a UntaggedValue>) -> TypeShape {
|
||||
match value.into() {
|
||||
UntaggedValue::Primitive(p) => TypeShape::from_primitive(p),
|
||||
UntaggedValue::Row(row) => TypeShape::from_dictionary(row),
|
||||
UntaggedValue::Table(table) => TypeShape::from_table(table.iter()),
|
||||
UntaggedValue::Error(_) => TypeShape::Error,
|
||||
UntaggedValue::Block(_) => TypeShape::Block,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PrettyDebug for TypeShape {
|
||||
fn pretty(&self) -> DebugDocBuilder {
|
||||
match self {
|
||||
TypeShape::Nothing => ty("nothing"),
|
||||
TypeShape::Int => ty("integer"),
|
||||
TypeShape::Decimal => ty("decimal"),
|
||||
TypeShape::Bytesize => ty("bytesize"),
|
||||
TypeShape::String => ty("string"),
|
||||
TypeShape::Line => ty("line"),
|
||||
TypeShape::ColumnPath => ty("column-path"),
|
||||
TypeShape::Pattern => ty("pattern"),
|
||||
TypeShape::Boolean => ty("boolean"),
|
||||
TypeShape::Date => ty("date"),
|
||||
TypeShape::Duration => ty("duration"),
|
||||
TypeShape::Path => ty("path"),
|
||||
TypeShape::Binary => ty("binary"),
|
||||
TypeShape::Error => b::error("error"),
|
||||
TypeShape::BeginningOfStream => b::keyword("beginning-of-stream"),
|
||||
TypeShape::EndOfStream => b::keyword("end-of-stream"),
|
||||
TypeShape::Row(row) => (b::kind("row")
|
||||
+ b::space()
|
||||
+ b::intersperse(
|
||||
row.iter().map(|(key, ty)| {
|
||||
(b::key(match key {
|
||||
Column::String(string) => string.clone(),
|
||||
Column::Value => "<value>".to_string(),
|
||||
}) + b::delimit("(", ty.pretty(), ")").into_kind())
|
||||
.nest()
|
||||
}),
|
||||
b::space(),
|
||||
)
|
||||
.nest())
|
||||
.nest(),
|
||||
|
||||
TypeShape::Table(table) => {
|
||||
let mut group: Group<DebugDoc, Vec<(usize, usize)>> = Group::new();
|
||||
|
||||
for (i, item) in table.iter().enumerate() {
|
||||
group.add(item.to_doc(), i);
|
||||
}
|
||||
|
||||
(b::kind("table") + b::space() + b::keyword("of")).group()
|
||||
+ b::space()
|
||||
+ (if group.len() == 1 {
|
||||
let (doc, _) = group.into_iter().nth(0).unwrap();
|
||||
DebugDocBuilder::from_doc(doc)
|
||||
} else {
|
||||
b::intersperse(
|
||||
group.into_iter().map(|(doc, rows)| {
|
||||
(b::intersperse(
|
||||
rows.iter().map(|(from, to)| {
|
||||
if from == to {
|
||||
b::description(from)
|
||||
} else {
|
||||
(b::description(from)
|
||||
+ b::space()
|
||||
+ b::keyword("to")
|
||||
+ b::space()
|
||||
+ b::description(to))
|
||||
.group()
|
||||
}
|
||||
}),
|
||||
b::description(", "),
|
||||
) + b::description(":")
|
||||
+ b::space()
|
||||
+ DebugDocBuilder::from_doc(doc))
|
||||
.nest()
|
||||
}),
|
||||
b::space(),
|
||||
)
|
||||
})
|
||||
}
|
||||
TypeShape::Block => ty("block"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, new)]
|
||||
struct DebugEntry<'a> {
|
||||
key: &'a Column,
|
||||
value: &'a TypeShape,
|
||||
}
|
||||
|
||||
impl<'a> PrettyDebug for DebugEntry<'a> {
|
||||
fn pretty(&self) -> DebugDocBuilder {
|
||||
(b::key(match self.key {
|
||||
Column::String(string) => string.clone(),
|
||||
Column::Value => "<value>".to_owned(),
|
||||
}) + b::delimit("(", self.value.pretty(), ")").into_kind())
|
||||
}
|
||||
}
|
||||
|
||||
fn ty(name: impl std::fmt::Display) -> DebugDocBuilder {
|
||||
b::kind(format!("{}", name))
|
||||
pub struct InlineRange {
|
||||
from: (InlineShape, RangeInclusion),
|
||||
to: (InlineShape, RangeInclusion),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
@ -209,6 +26,7 @@ pub enum InlineShape {
|
||||
Nothing,
|
||||
Int(BigInt),
|
||||
Decimal(BigDecimal),
|
||||
Range(Box<InlineRange>),
|
||||
Bytesize(u64),
|
||||
String(String),
|
||||
Line(String),
|
||||
@ -243,6 +61,15 @@ impl InlineShape {
|
||||
match primitive {
|
||||
Primitive::Nothing => InlineShape::Nothing,
|
||||
Primitive::Int(int) => InlineShape::Int(int.clone()),
|
||||
Primitive::Range(range) => {
|
||||
let (left, left_inclusion) = &range.from;
|
||||
let (right, right_inclusion) = &range.to;
|
||||
|
||||
InlineShape::Range(Box::new(InlineRange {
|
||||
from: (InlineShape::from_primitive(left), *left_inclusion),
|
||||
to: (InlineShape::from_primitive(right), *right_inclusion),
|
||||
}))
|
||||
}
|
||||
Primitive::Decimal(decimal) => InlineShape::Decimal(decimal.clone()),
|
||||
Primitive::Bytes(bytesize) => InlineShape::Bytesize(*bytesize),
|
||||
Primitive::String(string) => InlineShape::String(string.clone()),
|
||||
@ -314,6 +141,17 @@ impl PrettyDebug for FormatInlineShape {
|
||||
InlineShape::Nothing => b::blank(),
|
||||
InlineShape::Int(int) => b::primitive(format!("{}", int)),
|
||||
InlineShape::Decimal(decimal) => b::primitive(format!("{}", decimal)),
|
||||
InlineShape::Range(range) => {
|
||||
let (left, left_inclusion) = &range.from;
|
||||
let (right, right_inclusion) = &range.to;
|
||||
|
||||
let op = match (left_inclusion, right_inclusion) {
|
||||
(RangeInclusion::Inclusive, RangeInclusion::Exclusive) => "..",
|
||||
_ => unimplemented!("No syntax for ranges that aren't inclusive on the left and exclusive on the right")
|
||||
};
|
||||
|
||||
left.clone().format().pretty() + b::operator(op) + right.clone().format().pretty()
|
||||
}
|
||||
InlineShape::Bytesize(bytesize) => {
|
||||
let byte = byte_unit::Byte::from_bytes(*bytesize as u128);
|
||||
|
||||
@ -411,51 +249,6 @@ impl GroupedValue for Vec<(usize, usize)> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Group<K: Debug + Eq + Hash, V: GroupedValue> {
|
||||
values: indexmap::IndexMap<K, V>,
|
||||
}
|
||||
|
||||
impl<K, G> Group<K, G>
|
||||
where
|
||||
K: Debug + Eq + Hash,
|
||||
G: GroupedValue,
|
||||
{
|
||||
pub fn new() -> Group<K, G> {
|
||||
Group {
|
||||
values: indexmap::IndexMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.values.len()
|
||||
}
|
||||
|
||||
pub fn into_iter(self) -> impl Iterator<Item = (K, G)> {
|
||||
self.values.into_iter()
|
||||
}
|
||||
|
||||
pub fn add(&mut self, key: impl Into<K>, value: impl Into<G::Item>) {
|
||||
let key = key.into();
|
||||
let value = value.into();
|
||||
|
||||
let group = self.values.get_mut(&key);
|
||||
|
||||
match group {
|
||||
None => {
|
||||
self.values.insert(key, {
|
||||
let mut group = G::new();
|
||||
group.merge(value);
|
||||
group
|
||||
});
|
||||
}
|
||||
Some(group) => {
|
||||
group.merge(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
pub enum Column {
|
||||
String(String),
|
||||
|
@ -1,10 +1,10 @@
|
||||
use crate::data::base::coerce_compare;
|
||||
use crate::data::base::shape::{Column, InlineShape, TypeShape};
|
||||
use crate::data::base::shape::{Column, InlineShape};
|
||||
use crate::data::primitive::style_primitive;
|
||||
use chrono::DateTime;
|
||||
use nu_errors::ShellError;
|
||||
use nu_parser::Operator;
|
||||
use nu_protocol::{Primitive, UntaggedValue};
|
||||
use nu_parser::CompareOperator;
|
||||
use nu_protocol::{Primitive, Type, UntaggedValue};
|
||||
use nu_source::{DebugDocBuilder, PrettyDebug, Tagged};
|
||||
|
||||
pub fn date_from_str(s: Tagged<&str>) -> Result<UntaggedValue, ShellError> {
|
||||
@ -22,7 +22,7 @@ pub fn date_from_str(s: Tagged<&str>) -> Result<UntaggedValue, ShellError> {
|
||||
}
|
||||
|
||||
pub fn compare_values(
|
||||
operator: Operator,
|
||||
operator: &CompareOperator,
|
||||
left: &UntaggedValue,
|
||||
right: &UntaggedValue,
|
||||
) -> Result<bool, (&'static str, &'static str)> {
|
||||
@ -34,16 +34,15 @@ pub fn compare_values(
|
||||
use std::cmp::Ordering;
|
||||
|
||||
let result = match (operator, ordering) {
|
||||
(Operator::Equal, Ordering::Equal) => true,
|
||||
(Operator::NotEqual, Ordering::Less) | (Operator::NotEqual, Ordering::Greater) => {
|
||||
true
|
||||
}
|
||||
(Operator::LessThan, Ordering::Less) => true,
|
||||
(Operator::GreaterThan, Ordering::Greater) => true,
|
||||
(Operator::GreaterThanOrEqual, Ordering::Greater)
|
||||
| (Operator::GreaterThanOrEqual, Ordering::Equal) => true,
|
||||
(Operator::LessThanOrEqual, Ordering::Less)
|
||||
| (Operator::LessThanOrEqual, Ordering::Equal) => true,
|
||||
(CompareOperator::Equal, Ordering::Equal) => true,
|
||||
(CompareOperator::NotEqual, Ordering::Less)
|
||||
| (CompareOperator::NotEqual, Ordering::Greater) => true,
|
||||
(CompareOperator::LessThan, Ordering::Less) => true,
|
||||
(CompareOperator::GreaterThan, Ordering::Greater) => true,
|
||||
(CompareOperator::GreaterThanOrEqual, Ordering::Greater)
|
||||
| (CompareOperator::GreaterThanOrEqual, Ordering::Equal) => true,
|
||||
(CompareOperator::LessThanOrEqual, Ordering::Less)
|
||||
| (CompareOperator::LessThanOrEqual, Ordering::Equal) => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
@ -53,7 +52,7 @@ pub fn compare_values(
|
||||
}
|
||||
|
||||
pub fn format_type<'a>(value: impl Into<&'a UntaggedValue>, width: usize) -> String {
|
||||
TypeShape::from_value(value.into()).colored_string(width)
|
||||
Type::from_value(value.into()).colored_string(width)
|
||||
}
|
||||
|
||||
pub fn format_leaf<'a>(value: impl Into<&'a UntaggedValue>) -> DebugDocBuilder {
|
||||
|
@ -1,11 +1,20 @@
|
||||
use log::trace;
|
||||
use nu_errors::{CoerceInto, ShellError};
|
||||
use nu_protocol::{CallInfo, ColumnPath, Evaluate, Primitive, ShellTypeName, UntaggedValue, Value};
|
||||
use nu_source::{HasSpan, SpannedItem, Tagged, TaggedItem};
|
||||
use nu_protocol::{
|
||||
CallInfo, ColumnPath, Evaluate, Primitive, RangeInclusion, ShellTypeName, UntaggedValue, Value,
|
||||
};
|
||||
use nu_source::{HasSpan, Spanned, SpannedItem, Tagged, TaggedItem};
|
||||
use nu_value_ext::ValueExt;
|
||||
use serde::de;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Copy, Clone, Deserialize, Serialize)]
|
||||
pub struct NumericRange {
|
||||
pub from: (Spanned<u64>, RangeInclusion),
|
||||
pub to: (Spanned<u64>, RangeInclusion),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DeserializerItem<'de> {
|
||||
key_struct_field: Option<(String, &'de str)>,
|
||||
@ -406,6 +415,25 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut ConfigDeserializer<'de> {
|
||||
value: UntaggedValue::Primitive(Primitive::String(string)),
|
||||
..
|
||||
} => visit::<Tagged<String>, _>(string.tagged(tag), name, fields, visitor),
|
||||
Value {
|
||||
value: UntaggedValue::Primitive(Primitive::Range(range)),
|
||||
..
|
||||
} => {
|
||||
let (left, left_inclusion) = range.from;
|
||||
let (right, right_inclusion) = range.to;
|
||||
let left_span = left.span;
|
||||
let right_span = right.span;
|
||||
|
||||
let left = left.as_u64(left_span)?;
|
||||
let right = right.as_u64(right_span)?;
|
||||
|
||||
let numeric_range = NumericRange {
|
||||
from: (left.spanned(left_span), left_inclusion),
|
||||
to: (right.spanned(right_span), right_inclusion),
|
||||
};
|
||||
|
||||
visit::<Tagged<NumericRange>, _>(numeric_range.tagged(tag), name, fields, visitor)
|
||||
}
|
||||
|
||||
other => Err(ShellError::type_error(
|
||||
name,
|
||||
|
@ -6,8 +6,8 @@ use log::trace;
|
||||
use nu_errors::{ArgumentError, ShellError};
|
||||
use nu_parser::hir::{self, Expression, RawExpression};
|
||||
use nu_protocol::{
|
||||
ColumnPath, Evaluate, Primitive, Scope, TaggedDictBuilder, UnspannedPathMember, UntaggedValue,
|
||||
Value,
|
||||
ColumnPath, Evaluate, Primitive, RangeInclusion, Scope, TaggedDictBuilder, UnspannedPathMember,
|
||||
UntaggedValue, Value,
|
||||
};
|
||||
use nu_source::Text;
|
||||
|
||||
@ -40,7 +40,7 @@ pub(crate) fn evaluate_baseline_expr(
|
||||
|
||||
trace!("left={:?} right={:?}", left.value, right.value);
|
||||
|
||||
match apply_operator(**binary.op(), &left, &right) {
|
||||
match apply_operator(&**binary.op(), &left, &right) {
|
||||
Ok(result) => Ok(result.into_value(tag)),
|
||||
Err((left_type, right_type)) => Err(ShellError::coerce_error(
|
||||
left_type.spanned(binary.left().span),
|
||||
@ -48,6 +48,26 @@ pub(crate) fn evaluate_baseline_expr(
|
||||
)),
|
||||
}
|
||||
}
|
||||
RawExpression::Range(range) => {
|
||||
let left = range.left();
|
||||
let right = range.right();
|
||||
|
||||
let left = evaluate_baseline_expr(left, registry, scope, source)?;
|
||||
let right = evaluate_baseline_expr(right, registry, scope, source)?;
|
||||
let left_span = left.tag.span;
|
||||
let right_span = right.tag.span;
|
||||
|
||||
let left = (
|
||||
left.as_primitive()?.spanned(left_span),
|
||||
RangeInclusion::Inclusive,
|
||||
);
|
||||
let right = (
|
||||
right.as_primitive()?.spanned(right_span),
|
||||
RangeInclusion::Exclusive,
|
||||
);
|
||||
|
||||
Ok(UntaggedValue::range(left, right).into_value(tag))
|
||||
}
|
||||
RawExpression::List(list) => {
|
||||
let mut exprs = vec![];
|
||||
|
||||
|
@ -1,25 +1,24 @@
|
||||
use crate::data::value;
|
||||
use nu_parser::Operator;
|
||||
use nu_parser::CompareOperator;
|
||||
use nu_protocol::{Primitive, ShellTypeName, UntaggedValue, Value};
|
||||
use std::ops::Not;
|
||||
|
||||
pub fn apply_operator(
|
||||
op: Operator,
|
||||
op: &CompareOperator,
|
||||
left: &Value,
|
||||
right: &Value,
|
||||
) -> Result<UntaggedValue, (&'static str, &'static str)> {
|
||||
match op {
|
||||
Operator::Equal
|
||||
| Operator::NotEqual
|
||||
| Operator::LessThan
|
||||
| Operator::GreaterThan
|
||||
| Operator::LessThanOrEqual
|
||||
| Operator::GreaterThanOrEqual => {
|
||||
match *op {
|
||||
CompareOperator::Equal
|
||||
| CompareOperator::NotEqual
|
||||
| CompareOperator::LessThan
|
||||
| CompareOperator::GreaterThan
|
||||
| CompareOperator::LessThanOrEqual
|
||||
| CompareOperator::GreaterThanOrEqual => {
|
||||
value::compare_values(op, left, right).map(UntaggedValue::boolean)
|
||||
}
|
||||
Operator::Dot => Ok(UntaggedValue::boolean(false)),
|
||||
Operator::Contains => contains(left, right).map(UntaggedValue::boolean),
|
||||
Operator::NotContains => contains(left, right)
|
||||
CompareOperator::Contains => contains(left, right).map(UntaggedValue::boolean),
|
||||
CompareOperator::NotContains => contains(left, right)
|
||||
.map(Not::not)
|
||||
.map(UntaggedValue::boolean),
|
||||
}
|
||||
|
@ -144,7 +144,8 @@ fn paint_flat_shape(flat_shape: &Spanned<FlatShape>, line: &str) -> String {
|
||||
FlatShape::CloseDelimiter(_) => Color::White.normal(),
|
||||
FlatShape::ItVariable => Color::Purple.bold(),
|
||||
FlatShape::Variable => Color::Purple.normal(),
|
||||
FlatShape::Operator => Color::Yellow.normal(),
|
||||
FlatShape::CompareOperator => Color::Yellow.normal(),
|
||||
FlatShape::DotDot => Color::Yellow.bold(),
|
||||
FlatShape::Dot => Color::White.normal(),
|
||||
FlatShape::InternalCommand => Color::Cyan.bold(),
|
||||
FlatShape::ExternalCommand => Color::Cyan.normal(),
|
||||
@ -160,7 +161,8 @@ fn paint_flat_shape(flat_shape: &Spanned<FlatShape>, line: &str) -> String {
|
||||
FlatShape::ShorthandFlag => Color::Black.bold(),
|
||||
FlatShape::Int => Color::Purple.bold(),
|
||||
FlatShape::Decimal => Color::Purple.bold(),
|
||||
FlatShape::Whitespace => Color::White.normal(),
|
||||
FlatShape::Whitespace | FlatShape::Separator => Color::White.normal(),
|
||||
FlatShape::Comment => Color::Black.bold(),
|
||||
FlatShape::Error => Color::Red.bold(),
|
||||
FlatShape::Size { number, unit } => {
|
||||
let number = number.slice(line);
|
||||
|
Reference in New Issue
Block a user