From 2da12aed5626e3f4b8417d13f767fb541c5c4f1f Mon Sep 17 00:00:00 2001 From: Yehuda Katz Date: Mon, 8 Jul 2019 21:31:26 -0700 Subject: [PATCH] Tests pass --- src/commands/cd.rs | 4 +- src/commands/classified.rs | 17 +++- src/commands/config.rs | 4 +- src/commands/from_ini.rs | 48 +++++++---- src/commands/from_json.rs | 45 ++++++---- src/commands/from_toml.rs | 42 +++++---- src/commands/from_xml.rs | 42 +++++---- src/commands/from_yaml.rs | 38 ++++---- src/commands/ls.rs | 4 +- src/commands/open.rs | 120 ++++++++++++++------------ src/commands/pick.rs | 2 +- src/commands/ps.rs | 2 +- src/commands/reject.rs | 11 ++- src/commands/size.rs | 21 +++-- src/commands/split_column.rs | 24 +++--- src/commands/to_json.rs | 6 +- src/commands/to_toml.rs | 40 +++++++-- src/commands/trim.rs | 5 +- src/commands/view.rs | 2 +- src/errors.rs | 162 +++++++++++++++++++---------------- src/evaluate/evaluator.rs | 18 ++-- src/object/base.rs | 19 ++-- src/object/config.rs | 6 +- src/object/dict.rs | 50 +++++++++-- src/object/files.rs | 26 +++--- src/object/process.rs | 20 ++--- src/object/types.rs | 51 ++--------- src/parser/parse/span.rs | 22 ++++- src/parser/parse_command.rs | 38 ++++---- src/parser/registry.rs | 4 +- src/plugins/inc.rs | 24 ++++-- src/stream.rs | 33 +++++-- 32 files changed, 557 insertions(+), 393 deletions(-) diff --git a/src/commands/cd.rs b/src/commands/cd.rs index 8d76b5cbd0..383b696e14 100644 --- a/src/commands/cd.rs +++ b/src/commands/cd.rs @@ -6,9 +6,9 @@ use std::path::PathBuf; pub fn cd(args: CommandArgs) -> Result { let env = args.env.lock().unwrap(); let latest = env.back().unwrap(); - let obj = latest.obj; + let obj = &latest.obj; - match obj.item { + match obj.item() { Value::Filesystem => { let cwd = latest.path().to_path_buf(); diff --git a/src/commands/classified.rs b/src/commands/classified.rs index d29715c779..93ef2b9782 100644 --- a/src/commands/classified.rs +++ b/src/commands/classified.rs @@ -86,6 +86,17 @@ crate enum ClassifiedCommand { External(ExternalCommand), } +impl ClassifiedCommand { + pub fn span(&self) -> Span { + match self { + ClassifiedCommand::Expr(token) => token.span(), + ClassifiedCommand::Internal(internal) => internal.name_span.into(), + ClassifiedCommand::Sink(sink) => sink.name_span.into(), + ClassifiedCommand::External(external) => external.name_span.into(), + } + } +} + crate struct SinkCommand { crate command: Arc, crate name_span: Option, @@ -190,6 +201,7 @@ impl ExternalCommand { ) -> Result { let stdin = input.stdin; let inputs: Vec> = input.objects.into_vec().await; + let name_span = self.name_span.clone(); trace!("-> {}", self.name); trace!("inputs = {:?}", inputs); @@ -320,9 +332,10 @@ impl ExternalCommand { let stdout = popen.stdout.take().unwrap(); let file = futures::io::AllowStdIo::new(stdout); let stream = Framed::new(file, LinesCodec {}); - let stream = stream.map(|line| Value::string(line.unwrap())); + let stream = + stream.map(move |line| Value::string(line.unwrap()).spanned(name_span)); Ok(ClassifiedInputStream::from_input_stream( - stream.boxed() as BoxStream<'static, Value> + stream.boxed() as BoxStream<'static, Spanned> )) } } diff --git a/src/commands/config.rs b/src/commands/config.rs index 839fe9c275..c28b31da20 100644 --- a/src/commands/config.rs +++ b/src/commands/config.rs @@ -55,7 +55,7 @@ pub fn config(args: CommandArgs) -> Result { .ok_or_else(|| ShellError::string(&format!("Missing key {} in config", key)))?; return Ok( - stream![value.clone()], // futures::stream::once(futures::future::ready(ReturnSuccess::Value(value.clone()))).into(), + stream![value.clone()].into(), // futures::stream::once(futures::future::ready(ReturnSuccess::Value(value.clone()))).into(), ); } @@ -99,7 +99,7 @@ pub fn config(args: CommandArgs) -> Result { } if args.len() == 0 { - return Ok(vec![Value::Object(result.into())].into()); + return Ok(vec![Value::Object(result.into()).spanned(args.name_span)].into()); } Err(ShellError::string(format!("Unimplemented"))) diff --git a/src/commands/from_ini.rs b/src/commands/from_ini.rs index d4697d0acc..863c2d6196 100644 --- a/src/commands/from_ini.rs +++ b/src/commands/from_ini.rs @@ -1,29 +1,41 @@ -use crate::object::{Dictionary, Primitive, Value}; +use crate::object::{Dictionary, Primitive, SpannedDictBuilder, Value}; use crate::prelude::*; use indexmap::IndexMap; use std::collections::HashMap; -fn convert_ini_second_to_nu_value(v: &HashMap) -> Value { - let mut second = Dictionary::new(IndexMap::new()); +fn convert_ini_second_to_nu_value( + v: &HashMap, + span: impl Into, +) -> Spanned { + let mut second = SpannedDictBuilder::new(span); + for (key, value) in v.into_iter() { - second.add( - key.clone(), - Value::Primitive(Primitive::String(value.clone())), - ); + second.insert(key.clone(), Primitive::String(value.clone())); } - Value::Object(second) -} -fn convert_ini_top_to_nu_value(v: &HashMap>) -> Value { - let mut top_level = Dictionary::new(IndexMap::new()); - for (key, value) in v.iter() { - top_level.add(key.clone(), convert_ini_second_to_nu_value(value)); - } - Value::Object(top_level) + + second.into_spanned_value() } -pub fn from_ini_string_to_value(s: String) -> Result> { +fn convert_ini_top_to_nu_value( + v: &HashMap>, + span: impl Into, +) -> Spanned { + let span = span.into(); + let mut top_level = SpannedDictBuilder::new(span); + + for (key, value) in v.iter() { + top_level.insert_spanned(key.clone(), convert_ini_second_to_nu_value(value, span)); + } + + top_level.into_spanned_value() +} + +pub fn from_ini_string_to_value( + s: String, + span: impl Into, +) -> Result, Box> { let v: HashMap> = serde_ini::from_str(&s)?; - Ok(convert_ini_top_to_nu_value(&v)) + Ok(convert_ini_top_to_nu_value(&v, span)) } pub fn from_ini(args: CommandArgs) -> Result { @@ -32,7 +44,7 @@ pub fn from_ini(args: CommandArgs) -> Result { Ok(out .values .map(move |a| match a.item { - Value::Primitive(Primitive::String(s)) => match from_ini_string_to_value(s) { + Value::Primitive(Primitive::String(s)) => match from_ini_string_to_value(s, span) { Ok(x) => ReturnSuccess::value(x.spanned(a.span)), Err(e) => Err(ShellError::maybe_labeled_error( "Could not parse as INI", diff --git a/src/commands/from_json.rs b/src/commands/from_json.rs index edf8c1f29b..f91fa120bf 100644 --- a/src/commands/from_json.rs +++ b/src/commands/from_json.rs @@ -1,33 +1,46 @@ use crate::object::base::OF64; -use crate::object::{Dictionary, Primitive, Value}; +use crate::object::{Dictionary, Primitive, SpannedDictBuilder, Value}; use crate::prelude::*; -fn convert_json_value_to_nu_value(v: &serde_hjson::Value) -> Value { +fn convert_json_value_to_nu_value(v: &serde_hjson::Value, span: impl Into) -> Spanned { + let span = span.into(); + match v { - serde_hjson::Value::Null => Value::Primitive(Primitive::String(String::from(""))), - serde_hjson::Value::Bool(b) => Value::Primitive(Primitive::Boolean(*b)), - serde_hjson::Value::F64(n) => Value::Primitive(Primitive::Float(OF64::from(*n))), - serde_hjson::Value::U64(n) => Value::Primitive(Primitive::Int(*n as i64)), - serde_hjson::Value::I64(n) => Value::Primitive(Primitive::Int(*n as i64)), - serde_hjson::Value::String(s) => Value::Primitive(Primitive::String(String::from(s))), + serde_hjson::Value::Null => { + Value::Primitive(Primitive::String(String::from(""))).spanned(span) + } + serde_hjson::Value::Bool(b) => Value::Primitive(Primitive::Boolean(*b)).spanned(span), + serde_hjson::Value::F64(n) => { + Value::Primitive(Primitive::Float(OF64::from(*n))).spanned(span) + } + serde_hjson::Value::U64(n) => Value::Primitive(Primitive::Int(*n as i64)).spanned(span), + serde_hjson::Value::I64(n) => Value::Primitive(Primitive::Int(*n as i64)).spanned(span), + serde_hjson::Value::String(s) => { + Value::Primitive(Primitive::String(String::from(s))).spanned(span) + } serde_hjson::Value::Array(a) => Value::List( a.iter() - .map(|x| convert_json_value_to_nu_value(x).spanned_unknown()) + .map(|x| convert_json_value_to_nu_value(x, span)) .collect(), - ), + ) + .spanned(span), serde_hjson::Value::Object(o) => { - let mut collected = Dictionary::default(); + let mut collected = SpannedDictBuilder::new(span); for (k, v) in o.iter() { - collected.add(k.clone(), convert_json_value_to_nu_value(v)); + collected.add(k.clone(), convert_json_value_to_nu_value(v, span)); } - Value::Object(collected) + + collected.into_spanned_value() } } } -pub fn from_json_string_to_value(s: String) -> serde_hjson::Result { +pub fn from_json_string_to_value( + s: String, + span: impl Into, +) -> serde_hjson::Result> { let v: serde_hjson::Value = serde_hjson::from_str(&s)?; - Ok(convert_json_value_to_nu_value(&v)) + Ok(convert_json_value_to_nu_value(&v, span)) } pub fn from_json(args: CommandArgs) -> Result { @@ -36,7 +49,7 @@ pub fn from_json(args: CommandArgs) -> Result { Ok(out .values .map(move |a| match a.item { - Value::Primitive(Primitive::String(s)) => match from_json_string_to_value(s) { + Value::Primitive(Primitive::String(s)) => match from_json_string_to_value(s, span) { Ok(x) => ReturnSuccess::value(x.spanned(a.span)), Err(_) => Err(ShellError::maybe_labeled_error( "Could not parse as JSON", diff --git a/src/commands/from_toml.rs b/src/commands/from_toml.rs index a91c591726..a38058f5e8 100644 --- a/src/commands/from_toml.rs +++ b/src/commands/from_toml.rs @@ -1,32 +1,44 @@ use crate::object::base::OF64; -use crate::object::{Dictionary, Primitive, Value}; +use crate::object::{Dictionary, Primitive, SpannedDictBuilder, Value}; use crate::prelude::*; -fn convert_toml_value_to_nu_value(v: &toml::Value) -> Value { +fn convert_toml_value_to_nu_value(v: &toml::Value, span: impl Into) -> Spanned { + let span = span.into(); + match v { - toml::Value::Boolean(b) => Value::Primitive(Primitive::Boolean(*b)), - toml::Value::Integer(n) => Value::Primitive(Primitive::Int(*n)), - toml::Value::Float(n) => Value::Primitive(Primitive::Float(OF64::from(*n))), - toml::Value::String(s) => Value::Primitive(Primitive::String(String::from(s))), + toml::Value::Boolean(b) => Value::Primitive(Primitive::Boolean(*b)).spanned(span), + toml::Value::Integer(n) => Value::Primitive(Primitive::Int(*n)).spanned(span), + toml::Value::Float(n) => Value::Primitive(Primitive::Float(OF64::from(*n))).spanned(span), + toml::Value::String(s) => { + Value::Primitive(Primitive::String(String::from(s))).spanned(span) + } toml::Value::Array(a) => Value::List( a.iter() - .map(|x| convert_toml_value_to_nu_value(x).spanned_unknown()) + .map(|x| convert_toml_value_to_nu_value(x, span)) .collect(), - ), - toml::Value::Datetime(dt) => Value::Primitive(Primitive::String(dt.to_string())), + ) + .spanned(span), + toml::Value::Datetime(dt) => { + Value::Primitive(Primitive::String(dt.to_string())).spanned(span) + } toml::Value::Table(t) => { - let mut collected = Dictionary::default(); + let mut collected = SpannedDictBuilder::new(span); + for (k, v) in t.iter() { - collected.add(k.clone(), convert_toml_value_to_nu_value(v)); + collected.add(k.clone(), convert_toml_value_to_nu_value(v, span)); } - Value::Object(collected) + + collected.into_spanned_value() } } } -pub fn from_toml_string_to_value(s: String) -> Result> { +pub fn from_toml_string_to_value( + s: String, + span: impl Into, +) -> Result, Box> { let v: toml::Value = s.parse::()?; - Ok(convert_toml_value_to_nu_value(&v)) + Ok(convert_toml_value_to_nu_value(&v, span)) } pub fn from_toml(args: CommandArgs) -> Result { @@ -35,7 +47,7 @@ pub fn from_toml(args: CommandArgs) -> Result { Ok(out .values .map(move |a| match a.item { - Value::Primitive(Primitive::String(s)) => match from_toml_string_to_value(s) { + Value::Primitive(Primitive::String(s)) => match from_toml_string_to_value(s, span) { Ok(x) => ReturnSuccess::value(x.spanned(a.span)), Err(_) => Err(ShellError::maybe_labeled_error( "Could not parse as TOML", diff --git a/src/commands/from_xml.rs b/src/commands/from_xml.rs index 8a722ea3fc..9741592a8f 100644 --- a/src/commands/from_xml.rs +++ b/src/commands/from_xml.rs @@ -1,19 +1,27 @@ -use crate::object::{Dictionary, Primitive, Value}; +use crate::object::{Dictionary, Primitive, SpannedDictBuilder, Value}; use crate::prelude::*; -fn from_node_to_value<'a, 'd>(n: &roxmltree::Node<'a, 'd>) -> Value { +fn from_node_to_value<'a, 'd>( + n: &roxmltree::Node<'a, 'd>, + span: impl Into, +) -> Spanned { + let span = span.into(); + if n.is_element() { let name = n.tag_name().name().trim().to_string(); let mut children_values = vec![]; for c in n.children() { - children_values.push(from_node_to_value(&c)); + children_values.push(from_node_to_value(&c, span)); } let children_values: Vec> = children_values .into_iter() .filter(|x| match x { - Value::Primitive(Primitive::String(f)) => { + Spanned { + item: Value::Primitive(Primitive::String(f)), + .. + } => { if f.trim() == "" { false } else { @@ -22,31 +30,33 @@ fn from_node_to_value<'a, 'd>(n: &roxmltree::Node<'a, 'd>) -> Value { } _ => true, }) - .map(|v| v.spanned_unknown()) .collect(); let mut collected = Dictionary::default(); - collected.add(name.clone(), Value::List(children_values)); + collected.add(name.clone(), Value::List(children_values).spanned(span)); - Value::Object(collected) + collected.into_spanned_value() } else if n.is_comment() { - Value::string("") + Value::string("").spanned(span) } else if n.is_pi() { - Value::string("") + Value::string("").spanned(span) } else if n.is_text() { - Value::string(n.text().unwrap()) + Value::string(n.text().unwrap()).spanned(span) } else { - Value::string("") + Value::string("").spanned(span) } } -fn from_document_to_value(d: &roxmltree::Document) -> Value { - from_node_to_value(&d.root_element()) +fn from_document_to_value(d: &roxmltree::Document, span: impl Into) -> Spanned { + from_node_to_value(&d.root_element(), span) } -pub fn from_xml_string_to_value(s: String) -> Result> { +pub fn from_xml_string_to_value( + s: String, + span: impl Into, +) -> Result, Box> { let parsed = roxmltree::Document::parse(&s)?; - Ok(from_document_to_value(&parsed)) + Ok(from_document_to_value(&parsed, span)) } pub fn from_xml(args: CommandArgs) -> Result { @@ -55,7 +65,7 @@ pub fn from_xml(args: CommandArgs) -> Result { Ok(out .values .map(move |a| match a.item { - Value::Primitive(Primitive::String(s)) => match from_xml_string_to_value(s) { + Value::Primitive(Primitive::String(s)) => match from_xml_string_to_value(s, span) { Ok(x) => ReturnSuccess::value(x.spanned(a.span)), Err(_) => Err(ShellError::maybe_labeled_error( "Could not parse as XML", diff --git a/src/commands/from_yaml.rs b/src/commands/from_yaml.rs index b4679fdb78..0568ddce74 100644 --- a/src/commands/from_yaml.rs +++ b/src/commands/from_yaml.rs @@ -1,42 +1,50 @@ use crate::object::base::OF64; -use crate::object::{Dictionary, Primitive, Value}; +use crate::object::{Dictionary, Primitive, SpannedDictBuilder, Value}; use crate::prelude::*; -fn convert_yaml_value_to_nu_value(v: &serde_yaml::Value) -> Value { +fn convert_yaml_value_to_nu_value(v: &serde_yaml::Value, span: impl Into) -> Spanned { + let span = span.into(); + match v { - serde_yaml::Value::Bool(b) => Value::Primitive(Primitive::Boolean(*b)), + serde_yaml::Value::Bool(b) => Value::Primitive(Primitive::Boolean(*b)).spanned(span), serde_yaml::Value::Number(n) if n.is_i64() => { - Value::Primitive(Primitive::Int(n.as_i64().unwrap())) + Value::Primitive(Primitive::Int(n.as_i64().unwrap())).spanned(span) } serde_yaml::Value::Number(n) if n.is_f64() => { - Value::Primitive(Primitive::Float(OF64::from(n.as_f64().unwrap()))) + Value::Primitive(Primitive::Float(OF64::from(n.as_f64().unwrap()))).spanned(span) } - serde_yaml::Value::String(s) => Value::string(s), + serde_yaml::Value::String(s) => Value::string(s).spanned(span), serde_yaml::Value::Sequence(a) => Value::List( a.iter() - .map(|x| convert_yaml_value_to_nu_value(x).spanned_unknown()) + .map(|x| convert_yaml_value_to_nu_value(x, span)) .collect(), - ), + ) + .spanned(span), serde_yaml::Value::Mapping(t) => { - let mut collected = Dictionary::default(); + let mut collected = SpannedDictBuilder::new(span); + for (k, v) in t.iter() { match k { serde_yaml::Value::String(k) => { - collected.add(k.clone(), convert_yaml_value_to_nu_value(v)); + collected.add(k.clone(), convert_yaml_value_to_nu_value(v, span)); } _ => unimplemented!("Unknown key type"), } } - Value::Object(collected) + + collected.into_spanned_value() } - serde_yaml::Value::Null => Value::Primitive(Primitive::Nothing), + serde_yaml::Value::Null => Value::Primitive(Primitive::Nothing).spanned(span), x => unimplemented!("Unsupported yaml case: {:?}", x), } } -pub fn from_yaml_string_to_value(s: String) -> serde_yaml::Result { +pub fn from_yaml_string_to_value( + s: String, + span: impl Into, +) -> serde_yaml::Result> { let v: serde_yaml::Value = serde_yaml::from_str(&s)?; - Ok(convert_yaml_value_to_nu_value(&v)) + Ok(convert_yaml_value_to_nu_value(&v, span)) } pub fn from_yaml(args: CommandArgs) -> Result { @@ -45,7 +53,7 @@ pub fn from_yaml(args: CommandArgs) -> Result { Ok(out .values .map(move |a| match a.item { - Value::Primitive(Primitive::String(s)) => match from_yaml_string_to_value(s) { + Value::Primitive(Primitive::String(s)) => match from_yaml_string_to_value(s, span) { Ok(x) => ReturnSuccess::value(x.spanned(a.span)), Err(_) => Err(ShellError::maybe_labeled_error( "Could not parse as YAML", diff --git a/src/commands/ls.rs b/src/commands/ls.rs index 8181e9cea3..ad4c5a723a 100644 --- a/src/commands/ls.rs +++ b/src/commands/ls.rs @@ -44,8 +44,8 @@ pub fn ls(args: CommandArgs) -> Result { let mut shell_entries = VecDeque::new(); for entry in entries { - let value = Value::Object(dir_entry_dict(&entry?)?); - shell_entries.push_back(ReturnSuccess::value(value.spanned_unknown())) + let value = dir_entry_dict(&entry?, args.name_span)?; + shell_entries.push_back(ReturnSuccess::value(value)) } Ok(shell_entries.to_output_stream()) } diff --git a/src/commands/open.rs b/src/commands/open.rs index 72440bea79..14e253d33d 100644 --- a/src/commands/open.rs +++ b/src/commands/open.rs @@ -155,60 +155,72 @@ pub fn parse_as_value( name_span: Option, ) -> Result, ShellError> { match extension { - Some(x) if x == "toml" => crate::commands::from_toml::from_toml_string_to_value(contents) - .map(|c| c.spanned(contents_span)) - .map_err(move |_| { - ShellError::maybe_labeled_error( - "Could not open as TOML", - "could not open as TOML", - name_span, - ) - }), - Some(x) if x == "json" => crate::commands::from_json::from_json_string_to_value(contents) - .map(|c| c.spanned(contents_span)) - .map_err(move |_| { - ShellError::maybe_labeled_error( - "Could not open as JSON", - "could not open as JSON", - name_span, - ) - }), - Some(x) if x == "ini" => crate::commands::from_ini::from_ini_string_to_value(contents) - .map(|c| c.spanned(contents_span)) - .map_err(move |_| { - ShellError::maybe_labeled_error( - "Could not open as INI", - "could not open as INI", - name_span, - ) - }), - Some(x) if x == "xml" => crate::commands::from_xml::from_xml_string_to_value(contents) - .map(|c| c.spanned(contents_span)) - .map_err(move |_| { - ShellError::maybe_labeled_error( - "Could not open as XML", - "could not open as XML", - name_span, - ) - }), - Some(x) if x == "yml" => crate::commands::from_yaml::from_yaml_string_to_value(contents) - .map(|c| c.spanned(contents_span)) - .map_err(move |_| { - ShellError::maybe_labeled_error( - "Could not open as YAML", - "could not open as YAML", - name_span, - ) - }), - Some(x) if x == "yaml" => crate::commands::from_yaml::from_yaml_string_to_value(contents) - .map(|c| c.spanned(contents_span)) - .map_err(move |_| { - ShellError::maybe_labeled_error( - "Could not open as YAML", - "could not open as YAML", - name_span, - ) - }), + Some(x) if x == "toml" => { + crate::commands::from_toml::from_toml_string_to_value(contents, contents_span) + .map(|c| c.spanned(contents_span)) + .map_err(move |_| { + ShellError::maybe_labeled_error( + "Could not open as TOML", + "could not open as TOML", + name_span, + ) + }) + } + Some(x) if x == "json" => { + crate::commands::from_json::from_json_string_to_value(contents, contents_span) + .map(|c| c.spanned(contents_span)) + .map_err(move |_| { + ShellError::maybe_labeled_error( + "Could not open as JSON", + "could not open as JSON", + name_span, + ) + }) + } + Some(x) if x == "ini" => { + crate::commands::from_ini::from_ini_string_to_value(contents, contents_span) + .map(|c| c.spanned(contents_span)) + .map_err(move |_| { + ShellError::maybe_labeled_error( + "Could not open as INI", + "could not open as INI", + name_span, + ) + }) + } + Some(x) if x == "xml" => { + crate::commands::from_xml::from_xml_string_to_value(contents, contents_span).map_err( + move |_| { + ShellError::maybe_labeled_error( + "Could not open as XML", + "could not open as XML", + name_span, + ) + }, + ) + } + Some(x) if x == "yml" => { + crate::commands::from_yaml::from_yaml_string_to_value(contents, contents_span).map_err( + move |_| { + ShellError::maybe_labeled_error( + "Could not open as YAML", + "could not open as YAML", + name_span, + ) + }, + ) + } + Some(x) if x == "yaml" => { + crate::commands::from_yaml::from_yaml_string_to_value(contents, contents_span).map_err( + move |_| { + ShellError::maybe_labeled_error( + "Could not open as YAML", + "could not open as YAML", + name_span, + ) + }, + ) + } _ => Ok(Value::string(contents).spanned(contents_span)), } } diff --git a/src/commands/pick.rs b/src/commands/pick.rs index e4b2c35b72..d9f42aa6b1 100644 --- a/src/commands/pick.rs +++ b/src/commands/pick.rs @@ -18,7 +18,7 @@ pub fn pick(args: CommandArgs) -> Result { let objects = input .values - .map(move |value| Value::Object(select_fields(&value.item, &fields)).spanned(value.span)); + .map(move |value| select_fields(&value.item, &fields, value.span)); Ok(objects.from_input_stream()) } diff --git a/src/commands/ps.rs b/src/commands/ps.rs index d2be9c0ddc..5336ec97f0 100644 --- a/src/commands/ps.rs +++ b/src/commands/ps.rs @@ -11,7 +11,7 @@ pub fn ps(args: CommandArgs) -> Result { let list = list .into_iter() - .map(|(item, process)| Value::Object(process_dict(process)).spanned(args.name_span)) + .map(|(item, process)| process_dict(process, args.name_span)) .collect::>(); Ok(list.from_input_stream()) diff --git a/src/commands/reject.rs b/src/commands/reject.rs index 7fb0161c64..fc53aaea9c 100644 --- a/src/commands/reject.rs +++ b/src/commands/reject.rs @@ -4,6 +4,8 @@ use crate::object::Value; use crate::prelude::*; pub fn reject(args: CommandArgs) -> Result { + let name_span = args.name_span; + if args.len() == 0 { return Err(ShellError::maybe_labeled_error( "Reject requires fields", @@ -15,10 +17,11 @@ pub fn reject(args: CommandArgs) -> Result { let fields: Result, _> = args.positional_iter().map(|a| a.as_string()).collect(); let fields = fields?; - let stream = args - .input - .values - .map(move |item| Value::Object(reject_fields(&item, &fields)).spanned(args.name_span)); + let stream = args.input.values.map(move |item| { + reject_fields(&item, &fields, item.span) + .into_spanned_value() + .spanned(name_span) + }); Ok(stream.from_input_stream()) } diff --git a/src/commands/size.rs b/src/commands/size.rs index 041e8181a8..b94b55cb0c 100644 --- a/src/commands/size.rs +++ b/src/commands/size.rs @@ -1,6 +1,5 @@ use crate::errors::ShellError; -use crate::object::dict::Dictionary; -use crate::object::Value; +use crate::object::{SpannedDictBuilder, Value}; use crate::prelude::*; use std::fs::File; use std::io::prelude::*; @@ -30,14 +29,14 @@ pub fn size(args: CommandArgs) -> Result { let path = cwd.join(&name); let mut file = File::open(path)?; file.read_to_string(&mut contents)?; - list.push_back(count(&name, &contents).spanned(spanned_name).into()); + list.push_back(count(&name, &contents, spanned_name).into()); contents.clear(); } Ok(list.to_output_stream()) } -fn count(name: &str, contents: &str) -> Value { +fn count(name: &str, contents: &str, span: impl Into) -> Spanned { let mut lines: i64 = 0; let mut words: i64 = 0; let mut chars: i64 = 0; @@ -62,12 +61,12 @@ fn count(name: &str, contents: &str) -> Value { } } - let mut dict = Dictionary::default(); - dict.add("name", Value::string(name)); - dict.add("lines", Value::int(lines)); - dict.add("words", Value::int(words)); - dict.add("chars", Value::int(chars)); - dict.add("max length", Value::int(bytes)); + let mut dict = SpannedDictBuilder::new(span); + dict.insert("name", Value::string(name)); + dict.insert("lines", Value::int(lines)); + dict.insert("words", Value::int(words)); + dict.insert("chars", Value::int(chars)); + dict.insert("max length", Value::int(bytes)); - Value::Object(dict) + dict.into_spanned_value() } diff --git a/src/commands/split_column.rs b/src/commands/split_column.rs index 037e34b7cb..d2acde1db6 100644 --- a/src/commands/split_column.rs +++ b/src/commands/split_column.rs @@ -1,5 +1,5 @@ use crate::errors::ShellError; -use crate::object::{Primitive, Value}; +use crate::object::{Primitive, SpannedDictBuilder, Value}; use crate::prelude::*; use log::trace; @@ -36,29 +36,27 @@ pub fn split_column(args: CommandArgs) -> Result { gen_columns.push(format!("Column{}", i + 1)); } - let mut dict = crate::object::Dictionary::default(); + let mut dict = SpannedDictBuilder::new(v.span); for (&k, v) in split_result.iter().zip(gen_columns.iter()) { - dict.add(v.clone(), Value::Primitive(Primitive::String(k.into()))); + dict.insert(v.clone(), Primitive::String(k.into())); } - ReturnSuccess::value(Value::Object(dict).spanned(v.span)) + + ReturnSuccess::value(dict.into_spanned_value()) } else if split_result.len() == (positional.len() - 1) { - let mut dict = crate::object::Dictionary::default(); + let mut dict = SpannedDictBuilder::new(v.span); for (&k, v) in split_result.iter().zip(positional.iter().skip(1)) { - dict.add( + dict.insert( v.as_string().unwrap(), Value::Primitive(Primitive::String(k.into())), ); } - ReturnSuccess::value(Value::Object(dict).spanned(v.span)) + ReturnSuccess::value(dict.into_spanned_value()) } else { - let mut dict = crate::object::Dictionary::default(); + let mut dict = SpannedDictBuilder::new(v.span); for k in positional.iter().skip(1) { - dict.add( - k.as_string().unwrap().trim(), - Value::Primitive(Primitive::String("".into())), - ); + dict.insert(k.as_string().unwrap().trim(), Primitive::String("".into())); } - ReturnSuccess::value(Value::Object(dict).spanned(v.span)) + ReturnSuccess::value(dict.into_spanned_value()) } } _ => Err(ShellError::maybe_labeled_error( diff --git a/src/commands/to_json.rs b/src/commands/to_json.rs index 8563761b2f..d75586c219 100644 --- a/src/commands/to_json.rs +++ b/src/commands/to_json.rs @@ -43,17 +43,17 @@ pub fn value_to_json_value(v: &Value) -> serde_json::Value { pub fn to_json(args: CommandArgs) -> Result { let out = args.input; - let span = args.name_span; + let name_span = args.name_span; Ok(out .values .map(move |a| match serde_json::to_string(&a) { Ok(x) => { - ReturnSuccess::value(Value::Primitive(Primitive::String(x)).spanned(args.name_span)) + ReturnSuccess::value(Value::Primitive(Primitive::String(x)).spanned(name_span)) } Err(_) => Err(ShellError::maybe_labeled_error( "Can not convert to JSON string", "can not convert piped data to JSON string", - span, + name_span, )), }) .to_output_stream()) diff --git a/src/commands/to_toml.rs b/src/commands/to_toml.rs index 1c6543bc70..b23ca35195 100644 --- a/src/commands/to_toml.rs +++ b/src/commands/to_toml.rs @@ -33,18 +33,40 @@ pub fn value_to_toml_value(v: &Value) -> toml::Value { pub fn to_toml(args: CommandArgs) -> Result { let out = args.input; - let span = args.name_span; + let name_span = args.name_span; + Ok(out .values - .map(move |a| match toml::to_string(&a) { - Ok(x) => { - ReturnSuccess::value(Value::Primitive(Primitive::String(x)).spanned(args.name_span)) + .map(move |a| { + match toml::to_string(&a) { + Ok(val) => { + return ReturnSuccess::value( + Value::Primitive(Primitive::String(val)).spanned(name_span), + ) + } + + Err(err) => Err(ShellError::type_error( + "String", + format!("{:?} - {:?}", a.type_name(), err).spanned(name_span), + )), // toml::Value::String(String) => { + // return ReturnSuccess::value( + // Value::Primitive(Primitive::String(x)).spanned(name_span), + // ) + // } + // toml::Value::Integer(i64) => "Integer", + // toml::Value::Float(f64) => "Decimal", + // toml::Value::Boolean(bool) => "Boolean", + // toml::Value::Datetime(Datetime) => "Date", + // toml::Value::Array(Array) => "Array", + // toml::Value::Table(Table) => "Table", } - Err(_) => Err(ShellError::maybe_labeled_error( - "Can not convert to TOML string", - "can not convert piped data to TOML string", - span, - )), + // return Err(ShellError::type_error("String", ty.spanned(name_span))); + + // Err(_) => Err(ShellError::maybe_labeled_error( + // "Can not convert to TOML string", + // "can not convert piped data to TOML string", + // name_span, + // )), }) .to_output_stream()) } diff --git a/src/commands/trim.rs b/src/commands/trim.rs index 79b4acbedd..e4d66ffd2e 100644 --- a/src/commands/trim.rs +++ b/src/commands/trim.rs @@ -10,7 +10,10 @@ pub fn trim(args: CommandArgs) -> Result { Ok(input .values - .map(move |v| ReturnSuccess::value(String::check(&v)?.clone())) + .map(move |v| { + let string = String::extract(&v)?; + ReturnSuccess::value(Value::string(string.trim()).spanned(v.span)) + }) // Value::Primitive(Primitive::String(s)) => { // ReturnSuccess::value(Value::Primitive(Primitive::String(s.trim().into()))) // } diff --git a/src/commands/view.rs b/src/commands/view.rs index 3522b82fe7..06f34fc54d 100644 --- a/src/commands/view.rs +++ b/src/commands/view.rs @@ -46,5 +46,5 @@ pub fn view(args: CommandArgs) -> Result { let _ = printer.file(file.display().to_string()); - Ok(VecDeque::new().into()) + Ok(OutputStream::empty()) } diff --git a/src/errors.rs b/src/errors.rs index d78719f50a..17ccf38f5f 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -52,26 +52,9 @@ pub fn labelled( } #[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Serialize, Deserialize)] -pub enum ShellError { - String(StringError), - TypeError { - expected: String, - actual: Spanned>, - }, - MissingProperty { - subpath: Description, - expr: Description, - }, - ArgumentError { - command: String, - error: ArgumentError, - span: Span, - }, - Diagnostic(ShellDiagnostic), - CoerceError { - left: Spanned, - right: Spanned, - }, +pub struct ShellError { + error: ProximateShellError, + cause: Option>, } impl ShellError { @@ -79,10 +62,39 @@ impl ShellError { expected: impl Into, actual: Spanned>, ) -> ShellError { - ShellError::TypeError { + ProximateShellError::TypeError { expected: expected.into(), actual: actual.map(|i| Some(i.into())), } + .start() + } + + crate fn coerce_error( + left: Spanned>, + right: Spanned>, + ) -> ShellError { + ProximateShellError::CoerceError { + left: left.map(|l| l.into()), + right: right.map(|r| r.into()), + } + .start() + } + + crate fn missing_property(subpath: Description, expr: Description) -> ShellError { + ProximateShellError::MissingProperty { subpath, expr }.start() + } + + crate fn argument_error( + command: impl Into, + kind: ArgumentError, + span: Span, + ) -> ShellError { + ProximateShellError::ArgumentError { + command: command.into(), + error: kind, + span: span, + } + .start() } crate fn parse_error( @@ -97,40 +109,20 @@ impl ShellError { .with_label(Label::new_primary(Span::from(span.0))); ShellError::diagnostic(diagnostic) - // nom::Context::Code(span, kind) => { - // let diagnostic = - // Diagnostic::new(Severity::Error, format!("{}", kind.description())) - // .with_label(Label::new_primary(Span::from(span))); - - // ShellError::diagnostic(diagnostic) - // } - } // ParseError::UnrecognizedToken { - // token: (start, SpannedToken { token, .. }, end), - // expected, - // } => { - // let diagnostic = Diagnostic::new( - // Severity::Error, - // format!("Unexpected {:?}, expected {:?}", token, expected), - // ) - // .with_label(Label::new_primary(Span::from((start, end)))); - - // ShellError::diagnostic(diagnostic) - // } - // ParseError::User { error } => error, - // other => ShellError::string(format!("{:?}", other)), + } } } crate fn diagnostic(diagnostic: Diagnostic) -> ShellError { - ShellError::Diagnostic(ShellDiagnostic { diagnostic }) + ProximateShellError::Diagnostic(ShellDiagnostic { diagnostic }).start() } crate fn to_diagnostic(self) -> Diagnostic { - match self { - ShellError::String(StringError { title, .. }) => { + match self.error { + ProximateShellError::String(StringError { title, .. }) => { Diagnostic::new(Severity::Error, title) } - ShellError::ArgumentError { + ProximateShellError::ArgumentError { command, error, span, @@ -166,7 +158,7 @@ impl ShellError { ) .with_label(Label::new_primary(span)), }, - ShellError::TypeError { + ProximateShellError::TypeError { expected, actual: Spanned { @@ -178,13 +170,13 @@ impl ShellError { .with_message(format!("Expected {}, found {}", expected, actual)), ), - ShellError::TypeError { + ProximateShellError::TypeError { expected, actual: Spanned { item: None, span }, } => Diagnostic::new(Severity::Error, "Type Error") .with_label(Label::new_primary(span).with_message(expected)), - ShellError::MissingProperty { subpath, expr } => { + ProximateShellError::MissingProperty { subpath, expr } => { let subpath = subpath.into_label(); let expr = expr.into_label(); @@ -202,8 +194,8 @@ impl ShellError { diag } - ShellError::Diagnostic(diag) => diag.diagnostic, - ShellError::CoerceError { left, right } => { + ProximateShellError::Diagnostic(diag) => diag.diagnostic, + ProximateShellError::CoerceError { left, right } => { Diagnostic::new(Severity::Error, "Coercion error") .with_label(Label::new_primary(left.span).with_message(left.item)) .with_label(Label::new_secondary(right.span).with_message(right.item)) @@ -237,7 +229,7 @@ impl ShellError { } pub fn string(title: impl Into) -> ShellError { - ShellError::String(StringError::new(title.into(), Value::nothing())) + ProximateShellError::String(StringError::new(title.into(), Value::nothing())).start() } crate fn unimplemented(title: impl Into) -> ShellError { @@ -249,6 +241,37 @@ impl ShellError { } } +#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Serialize, Deserialize)] +pub enum ProximateShellError { + String(StringError), + TypeError { + expected: String, + actual: Spanned>, + }, + MissingProperty { + subpath: Description, + expr: Description, + }, + ArgumentError { + command: String, + error: ArgumentError, + span: Span, + }, + Diagnostic(ShellDiagnostic), + CoerceError { + left: Spanned, + right: Spanned, + }, +} +impl ProximateShellError { + fn start(self) -> ShellError { + ShellError { + cause: None, + error: self, + } + } +} + #[derive(Debug, Clone)] pub struct ShellDiagnostic { crate diagnostic: Diagnostic, @@ -322,13 +345,13 @@ pub struct StringError { impl std::fmt::Display for ShellError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match self { - ShellError::String(s) => write!(f, "{}", &s.title), - ShellError::TypeError { .. } => write!(f, "TypeError"), - ShellError::MissingProperty { .. } => write!(f, "MissingProperty"), - ShellError::ArgumentError { .. } => write!(f, "ArgumentError"), - ShellError::Diagnostic(_) => write!(f, ""), - ShellError::CoerceError { .. } => write!(f, "CoerceError"), + match &self.error { + ProximateShellError::String(s) => write!(f, "{}", &s.title), + ProximateShellError::TypeError { .. } => write!(f, "TypeError"), + ProximateShellError::MissingProperty { .. } => write!(f, "MissingProperty"), + ProximateShellError::ArgumentError { .. } => write!(f, "ArgumentError"), + ProximateShellError::Diagnostic(_) => write!(f, ""), + ProximateShellError::CoerceError { .. } => write!(f, "CoerceError"), } } } @@ -337,45 +360,40 @@ impl std::error::Error for ShellError {} impl std::convert::From for ShellError { fn from(input: std::io::Error) -> ShellError { - ShellError::String(StringError { + ProximateShellError::String(StringError { title: format!("{}", input), error: Value::nothing(), }) + .start() } } impl std::convert::From for ShellError { fn from(_input: futures_sink::VecSinkError) -> ShellError { - ShellError::String(StringError { + ProximateShellError::String(StringError { title: format!("Unexpected Vec Sink Error"), error: Value::nothing(), }) + .start() } } impl std::convert::From for ShellError { fn from(input: subprocess::PopenError) -> ShellError { - ShellError::String(StringError { + ProximateShellError::String(StringError { title: format!("{}", input), error: Value::nothing(), }) + .start() } } -// impl std::convert::From> for ShellError { -// fn from(input: nom::Err<(&str, nom::ErrorKind)>) -> ShellError { -// ShellError::String(StringError { -// title: format!("{:?}", input), -// error: Value::nothing(), -// }) -// } -// } - impl std::convert::From for ShellError { fn from(input: toml::ser::Error) -> ShellError { - ShellError::String(StringError { + ProximateShellError::String(StringError { title: format!("{:?}", input), error: Value::nothing(), }) + .start() } } diff --git a/src/evaluate/evaluator.rs b/src/evaluate/evaluator.rs index 0fcccee768..a8a3915e97 100644 --- a/src/evaluate/evaluator.rs +++ b/src/evaluate/evaluator.rs @@ -39,10 +39,10 @@ crate fn evaluate_baseline_expr( match left.compare(binary.op(), &*right) { Ok(result) => Ok(Spanned::from_item(Value::boolean(result), *expr.span())), - Err((left_type, right_type)) => Err(ShellError::CoerceError { - left: binary.left().copy_span(left_type), - right: binary.right().copy_span(right_type), - }), + Err((left_type, right_type)) => Err(ShellError::coerce_error( + binary.left().copy_span(left_type), + binary.right().copy_span(right_type), + )), } } RawExpression::Block(block) => Ok(Spanned::from_item( @@ -58,10 +58,10 @@ crate fn evaluate_baseline_expr( match next { None => { - return Err(ShellError::MissingProperty { - subpath: Description::from(item.spanned_type_name()), - expr: Description::from(name.clone()), - }) + return Err(ShellError::missing_property( + Description::from(item.spanned_type_name()), + Description::from(name.clone()), + )) } Some(next) => { item = Spanned::from_item( @@ -95,7 +95,7 @@ fn evaluate_reference( source: &Text, ) -> Result, ShellError> { match name { - hir::Variable::It(span) => Ok(Spanned::from_item(scope.it.item, span)), + hir::Variable::It(span) => Ok(Spanned::from_item(scope.it.item.clone(), span)), hir::Variable::Other(span) => Ok(scope .vars .get(span.slice(source)) diff --git a/src/object/base.rs b/src/object/base.rs index 73f144ea08..04662972ab 100644 --- a/src/object/base.rs +++ b/src/object/base.rs @@ -1,5 +1,6 @@ use crate::errors::ShellError; use crate::evaluate::{evaluate_baseline_expr, Scope}; +use crate::object::SpannedDictBuilder; use crate::parser::{hir, Operator, Span, Spanned}; use crate::prelude::*; use crate::Text; @@ -505,34 +506,34 @@ impl Value { } } -crate fn select_fields(obj: &Value, fields: &[String]) -> crate::object::Dictionary { - let mut out = crate::object::Dictionary::default(); +crate fn select_fields(obj: &Value, fields: &[String], span: impl Into) -> Spanned { + let mut out = SpannedDictBuilder::new(span); let descs = obj.data_descriptors(); for field in fields { match descs.iter().find(|d| d.name.is_string(field)) { - None => out.add(field, Value::nothing()), - Some(desc) => out.add(desc.clone(), obj.get_data(desc).borrow().clone()), + None => out.insert(field, Value::nothing()), + Some(desc) => out.insert(desc.clone(), obj.get_data(desc).borrow().clone()), } } - out + out.into_spanned_value() } -crate fn reject_fields(obj: &Value, fields: &[String]) -> crate::object::Dictionary { - let mut out = crate::object::Dictionary::default(); +crate fn reject_fields(obj: &Value, fields: &[String], span: impl Into) -> Spanned { + let mut out = SpannedDictBuilder::new(span); let descs = obj.data_descriptors(); for desc in descs { match desc { x if fields.iter().any(|field| *field == x) => continue, - _ => out.add(desc.clone(), obj.get_data(&desc).borrow().clone()), + _ => out.insert(desc.clone(), obj.get_data(&desc).borrow().clone()), } } - out + out.into_spanned_value() } #[allow(unused)] diff --git a/src/object/config.rs b/src/object/config.rs index f11fef027d..0860feb94b 100644 --- a/src/object/config.rs +++ b/src/object/config.rs @@ -27,10 +27,7 @@ crate fn write_config(config: &IndexMap>) -> Result<(), S touch(&filename)?; let contents = toml::to_string(&Config { - extra: config - .iter() - .map(|(k, v)| (k.clone(), v.item.clone())) - .collect(), + extra: config.iter().map(|(k, v)| (k.clone(), v.clone())).collect(), })?; fs::write(&filename, &contents)?; @@ -54,7 +51,6 @@ crate fn config(span: impl Into) -> Result .map_err(|err| ShellError::string(&format!("Couldn't read config file:\n{}", err)))?; let parsed: Config = toml::from_str(&contents) - .map(|v| v.spanned(span)) .map_err(|err| ShellError::string(&format!("Couldn't parse config file:\n{}", err)))?; Ok(parsed.extra) diff --git a/src/object/dict.rs b/src/object/dict.rs index c8f9965dac..ecad285079 100644 --- a/src/object/dict.rs +++ b/src/object/dict.rs @@ -21,8 +21,8 @@ impl PartialOrd for Dictionary { return this.partial_cmp(&that); } - let this: Vec<&Value> = self.entries.values().collect(); - let that: Vec<&Value> = self.entries.values().collect(); + let this: Vec<&Value> = self.entries.values().map(|v| v.item()).collect(); + let that: Vec<&Value> = self.entries.values().map(|v| v.item()).collect(); this.partial_cmp(&that) } @@ -49,8 +49,8 @@ impl Ord for Dictionary { return this.cmp(&that); } - let this: Vec<&Value> = self.entries.values().collect(); - let that: Vec<&Value> = self.entries.values().collect(); + let this: Vec<&Value> = self.entries.values().map(|v| v.item()).collect(); + let that: Vec<&Value> = self.entries.values().map(|v| v.item()).collect(); this.cmp(&that) } @@ -72,8 +72,8 @@ impl PartialEq for Dictionary { } impl Dictionary { - crate fn add(&mut self, name: impl Into, value: Value) { - self.entries.insert(name.into(), value); + crate fn add(&mut self, name: impl Into, value: impl Into>) { + self.entries.insert(name.into(), value.into()); } crate fn copy_dict(&self) -> Dictionary { @@ -115,6 +115,38 @@ impl Dictionary { } } +pub struct SpannedListBuilder { + span: Span, + list: Vec>, +} + +impl SpannedListBuilder { + pub fn new(span: impl Into) -> SpannedListBuilder { + SpannedListBuilder { + span: span.into(), + list: vec![], + } + } + + pub fn push(&mut self, value: impl Into) { + self.list.push(value.into().spanned(self.span)); + } + + pub fn insert_spanned(&mut self, value: impl Into>) { + self.list.push(value.into()); + } + + pub fn into_spanned_value(self) -> Spanned { + Value::List(self.list).spanned(self.span) + } +} + +impl From for Spanned { + fn from(input: SpannedListBuilder) -> Spanned { + input.into_spanned_value() + } +} + #[derive(Debug)] pub struct SpannedDictBuilder { span: Span, @@ -143,7 +175,11 @@ impl SpannedDictBuilder { } pub fn into_spanned_value(self) -> Spanned { - Value::Object(Dictionary { entries: self.dict }).spanned(self.span) + self.into_spanned_dict().map(Value::Object) + } + + pub fn into_spanned_dict(self) -> Spanned { + Dictionary { entries: self.dict }.spanned(self.span) } } diff --git a/src/object/files.rs b/src/object/files.rs index a169b3d1dd..210ff5405e 100644 --- a/src/object/files.rs +++ b/src/object/files.rs @@ -1,5 +1,6 @@ use crate::errors::ShellError; -use crate::object::{Dictionary, Value}; +use crate::object::{Dictionary, SpannedDictBuilder, Value}; +use crate::prelude::*; #[derive(Debug)] pub enum FileType { @@ -8,10 +9,13 @@ pub enum FileType { Symlink, } -crate fn dir_entry_dict(entry: &std::fs::DirEntry) -> Result { - let mut dict = Dictionary::default(); +crate fn dir_entry_dict( + entry: &std::fs::DirEntry, + span: impl Into, +) -> Result, ShellError> { + let mut dict = SpannedDictBuilder::new(span); let filename = entry.file_name(); - dict.add("file name", Value::string(filename.to_string_lossy())); + dict.insert("file name", Value::string(filename.to_string_lossy())); let metadata = entry.metadata()?; @@ -23,28 +27,28 @@ crate fn dir_entry_dict(entry: &std::fs::DirEntry) -> Result dict.add("created", Value::system_date(c)), + Ok(c) => dict.insert("created", Value::system_date(c)), Err(_) => {} } match metadata.accessed() { - Ok(a) => dict.add("accessed", Value::system_date(a)), + Ok(a) => dict.insert("accessed", Value::system_date(a)), Err(_) => {} } match metadata.modified() { - Ok(m) => dict.add("modified", Value::system_date(m)), + Ok(m) => dict.insert("modified", Value::system_date(m)), Err(_) => {} } - Ok(dict) + Ok(dict.into_spanned_value()) } diff --git a/src/object/process.rs b/src/object/process.rs index 830bef27da..ba716c5156 100644 --- a/src/object/process.rs +++ b/src/object/process.rs @@ -1,11 +1,11 @@ -use crate::object::base::Value; -use crate::object::dict::Dictionary; +use crate::object::{SpannedDictBuilder, Value}; +use crate::prelude::*; use itertools::join; use sysinfo::ProcessExt; -crate fn process_dict(proc: &sysinfo::Process) -> Dictionary { - let mut dict = Dictionary::default(); - dict.add("name", Value::string(proc.name())); +crate fn process_dict(proc: &sysinfo::Process, span: impl Into) -> Spanned { + let mut dict = SpannedDictBuilder::new(span); + dict.insert("name", Value::string(proc.name())); let cmd = proc.cmd(); @@ -15,10 +15,10 @@ crate fn process_dict(proc: &sysinfo::Process) -> Dictionary { Value::string(join(cmd, "")) }; - dict.add("cmd", cmd_value); - dict.add("cpu", Value::float(proc.cpu_usage() as f64)); - dict.add("pid", Value::int(proc.pid() as i64)); - dict.add("status", Value::string(proc.status().to_string())); + dict.insert("cmd", cmd_value); + dict.insert("cpu", Value::float(proc.cpu_usage() as f64)); + dict.insert("pid", Value::int(proc.pid() as i64)); + dict.insert("status", Value::string(proc.status().to_string())); - dict + dict.into_spanned_value() } diff --git a/src/object/types.rs b/src/object/types.rs index 46e52548e1..287cb4ef92 100644 --- a/src/object/types.rs +++ b/src/object/types.rs @@ -8,7 +8,6 @@ pub trait Type: std::fmt::Debug + Send { type Extractor: ExtractType; fn name(&self) -> &'static str; - fn check(&self, value: &'value Spanned) -> Result<&'value Spanned, ShellError>; fn coerce(&self) -> Option { None } @@ -28,10 +27,6 @@ impl Type for Any { fn name(&self) -> &'static str { "Any" } - - fn check(&self, value: &'value Spanned) -> Result<&'value Spanned, ShellError> { - Ok(value) - } } impl ExtractType for Spanned { @@ -39,7 +34,7 @@ impl ExtractType for Spanned { Ok(value.clone()) } - fn check(&self, value: &'value Spanned) -> Result<&'value Spanned, ShellError> { + fn check(value: &'value Spanned) -> Result<&'value Spanned, ShellError> { Ok(value) } } @@ -53,16 +48,6 @@ impl Type for Integer { fn name(&self) -> &'static str { "Integer" } - - fn check(&self, value: &'value Spanned) -> Result<&'value Spanned, ShellError> { - match value { - v @ Spanned { - item: Value::Primitive(Primitive::Int(_)), - .. - } => Ok(v), - other => Err(ShellError::type_error("Integer", other.spanned_type_name())), - } - } } impl ExtractType for i64 { @@ -76,7 +61,7 @@ impl ExtractType for i64 { } } - fn check(&self, value: &'value Spanned) -> Result<&'value Spanned, ShellError> { + fn check(value: &'value Spanned) -> Result<&'value Spanned, ShellError> { match value { v @ Spanned { item: Value::Primitive(Primitive::Int(_)), @@ -96,16 +81,6 @@ impl Type for NuString { fn name(&self) -> &'static str { "Integer" } - - fn check(&self, value: &'value Spanned) -> Result<&'value Spanned, ShellError> { - match value { - v @ Spanned { - item: Value::Primitive(Primitive::Int(_)), - .. - } => Ok(v), - other => Err(ShellError::type_error("Integer", other.spanned_type_name())), - } - } } impl ExtractType for String { @@ -119,13 +94,13 @@ impl ExtractType for String { } } - fn check(&self, value: &'value Spanned) -> Result<&'value Spanned, ShellError> { + fn check(value: &'value Spanned) -> Result<&'value Spanned, ShellError> { match value { v @ Spanned { - item: Value::Primitive(Primitive::Int(_)), + item: Value::Primitive(Primitive::String(_)), .. } => Ok(v), - other => Err(ShellError::type_error("Integer", other.spanned_type_name())), + other => Err(ShellError::type_error("String", other.spanned_type_name())), } } } @@ -139,8 +114,10 @@ impl Type for Block { fn name(&self) -> &'static str { "Block" } +} - fn check(&self, value: &'value Spanned) -> Result<&'value Spanned, ShellError> { +impl ExtractType for value::Block { + fn check(value: &'value Spanned) -> Result<&'value Spanned, ShellError> { match value { v @ Spanned { item: Value::Block(_), @@ -149,9 +126,7 @@ impl Type for Block { other => Err(ShellError::type_error("Block", other.spanned_type_name())), } } -} -impl ExtractType for value::Block { fn extract(value: &Spanned) -> Result { match value { Spanned { @@ -161,14 +136,4 @@ impl ExtractType for value::Block { other => Err(ShellError::type_error("Block", other.spanned_type_name())), } } - - fn check(&self, value: &'value Spanned) -> Result<&'value Spanned, ShellError> { - match value { - v @ Spanned { - item: Value::Block(_), - .. - } => Ok(v), - other => Err(ShellError::type_error("Block", other.spanned_type_name())), - } - } } diff --git a/src/parser/parse/span.rs b/src/parser/parse/span.rs index 7ed86e6a12..fb885e0c60 100644 --- a/src/parser/parse/span.rs +++ b/src/parser/parse/span.rs @@ -1,17 +1,31 @@ use crate::Text; use derive_new::new; use getset::Getters; -use serde_derive::{Deserialize, Serialize}; +use serde::{Serialize, Serializer}; +use serde_derive::Deserialize; -#[derive( - new, Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, Hash, Getters, -)] +#[derive(new, Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Deserialize, Hash, Getters)] #[get = "crate"] pub struct Spanned { pub span: Span, pub item: T, } +impl Serialize for Spanned { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.item.serialize(serializer) + } +} + +impl Spanned { + pub fn spanned(self, span: impl Into) -> Spanned { + Spanned::from_item(self.item, span.into()) + } +} + pub trait SpannedItem: Sized { fn spanned(self, span: impl Into) -> Spanned { Spanned::from_item(self, span.into()) diff --git a/src/parser/parse_command.rs b/src/parser/parse_command.rs index ff407231c1..8c7d5e7cfe 100644 --- a/src/parser/parse_command.rs +++ b/src/parser/parse_command.rs @@ -93,11 +93,11 @@ fn parse_command_tail( tail.move_to(pos); if tail.at_end() { - return Err(ShellError::ArgumentError { - command: config.name().clone(), - error: ArgumentError::MissingValueForName(name.to_string()), - span: flag.span, - }); + return Err(ShellError::argument_error( + config.name.clone(), + ArgumentError::MissingValueForName(name.to_string()), + flag.span, + )); } let expr = hir::baseline_parse_next_expr( @@ -118,11 +118,11 @@ fn parse_command_tail( tail.move_to(pos); if tail.at_end() { - return Err(ShellError::ArgumentError { - command: config.name().clone(), - error: ArgumentError::MissingValueForName(name.to_string()), - span: flag.span, - }); + return Err(ShellError::argument_error( + config.name().clone(), + ArgumentError::MissingValueForName(name.to_string()), + flag.span, + )); } let expr = hir::baseline_parse_next_expr( @@ -154,11 +154,11 @@ fn parse_command_tail( match arg { PositionalType::Mandatory(..) => { if tail.len() == 0 { - return Err(ShellError::ArgumentError { - command: config.name().clone(), - error: ArgumentError::MissingMandatoryPositional(arg.name().to_string()), - span: command_span, - }); + return Err(ShellError::argument_error( + config.name().clone(), + ArgumentError::MissingMandatoryPositional(arg.name().to_string()), + command_span, + )); } } @@ -215,11 +215,11 @@ fn extract_mandatory( let flag = tokens.extract(|t| t.as_flag(name, source)); match flag { - None => Err(ShellError::ArgumentError { - command: config.name().clone(), - error: ArgumentError::MissingMandatoryFlag(name.to_string()), + None => Err(ShellError::argument_error( + config.name().clone(), + ArgumentError::MissingMandatoryFlag(name.to_string()), span, - }), + )), Some((pos, flag)) => { tokens.remove(pos); diff --git a/src/parser/registry.rs b/src/parser/registry.rs index b753cb9aed..d168d9dbba 100644 --- a/src/parser/registry.rs +++ b/src/parser/registry.rs @@ -102,7 +102,7 @@ impl fmt::Debug for DebugPositional<'a> { None => write!(f, "None"), Some(positional) => f .debug_list() - .entries(positional.iter().map(|p| p.item().debug())) + .entries(positional.iter().map(|p| p.debug())) .finish(), } } @@ -119,7 +119,7 @@ impl fmt::Debug for DebugNamed<'a> { None => write!(f, "None"), Some(named) => f .debug_map() - .entries(named.iter().map(|(k, v)| (k, v.item().debug()))) + .entries(named.iter().map(|(k, v)| (k, v.debug()))) .finish(), } } diff --git a/src/plugins/inc.rs b/src/plugins/inc.rs index dbaeaa1d82..d301ab07ef 100644 --- a/src/plugins/inc.rs +++ b/src/plugins/inc.rs @@ -3,7 +3,7 @@ use nu::{ serve_plugin, Args, CommandConfig, Plugin, PositionalType, Primitive, ReturnValue, ShellError, Spanned, Value, }; -use nu::{Primitive, ReturnSuccess, ReturnValue, ShellError, Spanned, Value}; +use nu::{Primitive, ReturnSuccess, ReturnValue, ShellError, Spanned, SpannedItem, Value}; use serde::{Deserialize, Serialize}; use std::io; @@ -32,7 +32,7 @@ fn send_error(error: ShellError) { #[allow(non_camel_case_types)] pub enum NuCommand { init { params: Vec> }, - filter { params: Value }, + filter { params: Spanned }, quit, } @@ -62,13 +62,21 @@ fn main() -> Result<(), Box> { } } Ok(NuCommand::filter { params }) => match params { - Value::Primitive(Primitive::Int(i)) => { - send_response(vec![ReturnSuccess::value(Value::int(i + inc_by))]); + Spanned { + item: Value::Primitive(Primitive::Int(i)), + span, + } => { + send_response(vec![ReturnSuccess::value( + Value::int(i + inc_by).spanned(span), + )]); } - Value::Primitive(Primitive::Bytes(b)) => { - send_response(vec![ReturnSuccess::value(Value::bytes( - b + inc_by as u128, - ))]); + Spanned { + item: Value::Primitive(Primitive::Bytes(b)), + span, + } => { + send_response(vec![ReturnSuccess::value( + Value::bytes(b + inc_by as u128).spanned(span), + )]); } _ => { send_error(ShellError::string("Unrecognized type in stream")); diff --git a/src/stream.rs b/src/stream.rs index 9281831b89..cd94ddf3be 100644 --- a/src/stream.rs +++ b/src/stream.rs @@ -16,8 +16,8 @@ impl InputStream { } } -impl From> for InputStream { - fn from(input: BoxStream<'static, Value>) -> InputStream { +impl From>> for InputStream { + fn from(input: BoxStream<'static, Spanned>) -> InputStream { InputStream { values: input } } } @@ -30,8 +30,8 @@ impl From>> for InputStream { } } -impl From> for InputStream { - fn from(input: Vec) -> InputStream { +impl From>> for InputStream { + fn from(input: Vec>) -> InputStream { let mut list = VecDeque::default(); list.extend(input); @@ -46,6 +46,11 @@ pub struct OutputStream { } impl OutputStream { + pub fn empty() -> OutputStream { + let v: VecDeque = VecDeque::new(); + v.into() + } + pub fn from_input(input: impl Stream> + Send + 'static) -> OutputStream { OutputStream { values: input.map(ReturnSuccess::value).boxed(), @@ -61,8 +66,8 @@ impl From for OutputStream { } } -impl From> for OutputStream { - fn from(input: BoxStream<'static, Value>) -> OutputStream { +impl From>> for OutputStream { + fn from(input: BoxStream<'static, Spanned>) -> OutputStream { OutputStream { values: input.map(ReturnSuccess::value).boxed(), } @@ -83,6 +88,18 @@ impl From> for OutputStream { } } +impl From>> for OutputStream { + fn from(input: VecDeque>) -> OutputStream { + OutputStream { + values: input + .into_iter() + .map(|i| ReturnSuccess::value(i)) + .collect::>() + .boxed(), + } + } +} + impl From> for OutputStream { fn from(input: Vec) -> OutputStream { let mut list = VecDeque::default(); @@ -94,8 +111,8 @@ impl From> for OutputStream { } } -impl From> for OutputStream { - fn from(input: Vec) -> OutputStream { +impl From>> for OutputStream { + fn from(input: Vec>) -> OutputStream { let mut list = VecDeque::default(); list.extend(input.into_iter().map(ReturnSuccess::value));