This commit is contained in:
Yehuda Katz 2019-07-08 09:44:53 -07:00
parent 71adfb4cdc
commit 7b68739b52
47 changed files with 467 additions and 354 deletions

View File

@ -231,7 +231,7 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
let last = env.back().unwrap(); let last = env.back().unwrap();
(last.obj().clone(), last.path().display().to_string()) (last.obj().clone(), last.path().display().to_string())
}; };
let readline = match obj { let readline = match obj.item {
Value::Filesystem => rl.readline(&format!( Value::Filesystem => rl.readline(&format!(
"{}{}> ", "{}{}> ",
cwd, cwd,
@ -396,7 +396,7 @@ async fn process_line(readline: Result<String, ReadlineError>, ctx: &mut Context
} }
(Some(ClassifiedCommand::Sink(left)), None) => { (Some(ClassifiedCommand::Sink(left)), None) => {
let input_vec: Vec<Value> = input.objects.into_vec().await; let input_vec: Vec<Spanned<Value>> = input.objects.into_vec().await;
if let Err(err) = left.run(ctx, input_vec) { if let Err(err) = left.run(ctx, input_vec) {
return LineResult::Error(line.clone(), err); return LineResult::Error(line.clone(), err);
} }

View File

@ -22,7 +22,7 @@ pub fn autoview(args: SinkCommandArgs) -> Result<(), ShellError> {
Ok(()) Ok(())
} }
fn equal_shapes(input: &Vec<Value>) -> bool { fn equal_shapes(input: &Vec<Spanned<Value>>) -> bool {
let mut items = input.iter(); let mut items = input.iter();
let item = match items.next() { let item = match items.next() {

View File

@ -6,8 +6,9 @@ use std::path::PathBuf;
pub fn cd(args: CommandArgs) -> Result<OutputStream, ShellError> { pub fn cd(args: CommandArgs) -> Result<OutputStream, ShellError> {
let env = args.env.lock().unwrap(); let env = args.env.lock().unwrap();
let latest = env.back().unwrap(); let latest = env.back().unwrap();
let obj = latest.obj;
match latest.obj { match obj.item {
Value::Filesystem => { Value::Filesystem => {
let cwd = latest.path().to_path_buf(); let cwd = latest.path().to_path_buf();

View File

@ -59,24 +59,6 @@ impl ClassifiedInputStream {
} }
} }
pub fn into_vec(self) -> impl std::future::Future<Output = Vec<Value>> {
self.objects.into_vec()
}
crate fn from_vec(stream: VecDeque<Value>) -> ClassifiedInputStream {
ClassifiedInputStream {
objects: stream.into(),
stdin: None,
}
}
crate fn from_list(stream: Vec<Value>) -> ClassifiedInputStream {
ClassifiedInputStream {
objects: stream.into(),
stdin: None,
}
}
crate fn from_input_stream(stream: impl Into<InputStream>) -> ClassifiedInputStream { crate fn from_input_stream(stream: impl Into<InputStream>) -> ClassifiedInputStream {
ClassifiedInputStream { ClassifiedInputStream {
objects: stream.into(), objects: stream.into(),
@ -111,7 +93,11 @@ crate struct SinkCommand {
} }
impl SinkCommand { impl SinkCommand {
crate fn run(self, context: &mut Context, input: Vec<Value>) -> Result<(), ShellError> { crate fn run(
self,
context: &mut Context,
input: Vec<Spanned<Value>>,
) -> Result<(), ShellError> {
context.run_sink(self.command, self.name_span.clone(), self.args, input) context.run_sink(self.command, self.name_span.clone(), self.args, input)
} }
} }
@ -160,7 +146,11 @@ impl InternalCommand {
} }
CommandAction::Exit => match context.env.lock().unwrap().pop_back() { CommandAction::Exit => match context.env.lock().unwrap().pop_back() {
Some(Environment { Some(Environment {
obj: Value::Filesystem, obj:
Spanned {
item: Value::Filesystem,
..
},
.. ..
}) => std::process::exit(0), }) => std::process::exit(0),
None => std::process::exit(-1), None => std::process::exit(-1),
@ -199,7 +189,7 @@ impl ExternalCommand {
stream_next: StreamNext, stream_next: StreamNext,
) -> Result<ClassifiedInputStream, ShellError> { ) -> Result<ClassifiedInputStream, ShellError> {
let stdin = input.stdin; let stdin = input.stdin;
let inputs: Vec<Value> = input.objects.into_vec().await; let inputs: Vec<Spanned<Value>> = input.objects.into_vec().await;
trace!("-> {}", self.name); trace!("-> {}", self.name);
trace!("inputs = {:?}", inputs); trace!("inputs = {:?}", inputs);

View File

@ -7,7 +7,7 @@ use crate::parser::{
use crate::prelude::*; use crate::prelude::*;
use getset::Getters; use getset::Getters;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{ops::Try, path::PathBuf}; use std::path::PathBuf;
#[derive(Getters)] #[derive(Getters)]
#[get = "crate"] #[get = "crate"]
@ -49,26 +49,26 @@ pub struct SinkCommandArgs {
pub ctx: Context, pub ctx: Context,
pub name_span: Option<Span>, pub name_span: Option<Span>,
pub args: Args, pub args: Args,
pub input: Vec<Value>, pub input: Vec<Spanned<Value>>,
} }
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub enum CommandAction { pub enum CommandAction {
ChangePath(PathBuf), ChangePath(PathBuf),
Enter(Value), Enter(Spanned<Value>),
Exit, Exit,
} }
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub enum ReturnSuccess { pub enum ReturnSuccess {
Value(Value), Value(Spanned<Value>),
Action(CommandAction), Action(CommandAction),
} }
pub type ReturnValue = Result<ReturnSuccess, ShellError>; pub type ReturnValue = Result<ReturnSuccess, ShellError>;
impl From<Value> for ReturnValue { impl From<Spanned<Value>> for ReturnValue {
fn from(input: Value) -> ReturnValue { fn from(input: Spanned<Value>) -> ReturnValue {
Ok(ReturnSuccess::Value(input)) Ok(ReturnSuccess::Value(input))
} }
} }
@ -78,8 +78,12 @@ impl ReturnSuccess {
Ok(ReturnSuccess::Action(CommandAction::ChangePath(path))) Ok(ReturnSuccess::Action(CommandAction::ChangePath(path)))
} }
pub fn value(input: Value) -> ReturnValue { pub fn value(input: impl Into<Spanned<Value>>) -> ReturnValue {
Ok(ReturnSuccess::Value(input)) Ok(ReturnSuccess::Value(input.into()))
}
pub fn spanned_value(input: Value, span: Span) -> ReturnValue {
Ok(ReturnSuccess::Value(Spanned::from_item(input, span)))
} }
} }

View File

@ -1,4 +1,3 @@
#[macro_use]
use crate::prelude::*; use crate::prelude::*;
use crate::errors::ShellError; use crate::errors::ShellError;
@ -44,7 +43,7 @@ impl Command for Config {
} }
pub fn config(args: CommandArgs) -> Result<OutputStream, ShellError> { pub fn config(args: CommandArgs) -> Result<OutputStream, ShellError> {
let mut result = crate::object::config::config()?; let mut result = crate::object::config::config(args.name_span)?;
trace!("{:#?}", args.args.positional); trace!("{:#?}", args.args.positional);
trace!("{:#?}", args.args.named); trace!("{:#?}", args.args.named);
@ -56,7 +55,7 @@ pub fn config(args: CommandArgs) -> Result<OutputStream, ShellError> {
.ok_or_else(|| ShellError::string(&format!("Missing key {} in config", key)))?; .ok_or_else(|| ShellError::string(&format!("Missing key {} in config", key)))?;
return Ok( return Ok(
vec![value.clone()].into(), // futures::stream::once(futures::future::ready(ReturnSuccess::Value(value.clone()))).into(), stream![value.clone()], // futures::stream::once(futures::future::ready(ReturnSuccess::Value(value.clone()))).into(),
); );
} }
@ -66,16 +65,21 @@ pub fn config(args: CommandArgs) -> Result<OutputStream, ShellError> {
config::write_config(&result)?; config::write_config(&result)?;
return Ok(stream![Value::Object(result.into())].from_input_stream()); return Ok(
stream![Spanned::from_item(Value::Object(result.into()), v.span())]
.from_input_stream(),
);
} }
} }
if let Some(_) = args.get("clear") { if let Some(c) = args.get("clear") {
result.clear(); result.clear();
config::write_config(&result)?; config::write_config(&result)?;
return Ok(stream![Value::Object(result.into())].from_input_stream()); return Ok(
stream![Spanned::from_item(Value::Object(result.into()), c.span())].from_input_stream(),
);
} }
if let Some(v) = args.get("remove") { if let Some(v) = args.get("remove") {
@ -90,7 +94,7 @@ pub fn config(args: CommandArgs) -> Result<OutputStream, ShellError> {
))); )));
} }
let obj = VecDeque::from_iter(vec![Value::Object(result.into())]); let obj = VecDeque::from_iter(vec![Value::Object(result.into()).spanned(v)]);
return Ok(obj.from_input_stream()); return Ok(obj.from_input_stream());
} }

View File

@ -49,7 +49,7 @@ pub fn enter(args: CommandArgs) -> Result<OutputStream, ShellError> {
let full_path = PathBuf::from(cwd); let full_path = PathBuf::from(cwd);
let (file_extension, contents) = match &args.expect_nth(0)?.item { let (file_extension, contents, contents_span) = match &args.expect_nth(0)?.item {
Value::Primitive(Primitive::String(s)) => fetch(&full_path, s, args.expect_nth(0)?.span)?, Value::Primitive(Primitive::String(s)) => fetch(&full_path, s, args.expect_nth(0)?.span)?,
_ => { _ => {
return Err(ShellError::labeled_error( return Err(ShellError::labeled_error(
@ -90,7 +90,7 @@ pub fn enter(args: CommandArgs) -> Result<OutputStream, ShellError> {
}; };
stream.push_back(Ok(ReturnSuccess::Action(CommandAction::Enter( stream.push_back(Ok(ReturnSuccess::Action(CommandAction::Enter(
parse_as_value(file_extension, contents, span)?, parse_as_value(file_extension, contents, contents_span, span)?,
)))); ))));
Ok(stream.into()) Ok(stream.into())

View File

@ -31,9 +31,9 @@ pub fn from_ini(args: CommandArgs) -> Result<OutputStream, ShellError> {
let span = args.name_span; let span = args.name_span;
Ok(out Ok(out
.values .values
.map(move |a| match a { .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) {
Ok(x) => Ok(ReturnSuccess::Value(x)), Ok(x) => ReturnSuccess::value(x.spanned(a.span)),
Err(e) => Err(ShellError::maybe_labeled_error( Err(e) => Err(ShellError::maybe_labeled_error(
"Could not parse as INI", "Could not parse as INI",
format!("{:#?}", e), format!("{:#?}", e),

View File

@ -12,7 +12,7 @@ fn convert_json_value_to_nu_value(v: &serde_hjson::Value) -> Value {
serde_hjson::Value::String(s) => Value::Primitive(Primitive::String(String::from(s))), serde_hjson::Value::String(s) => Value::Primitive(Primitive::String(String::from(s))),
serde_hjson::Value::Array(a) => Value::List( serde_hjson::Value::Array(a) => Value::List(
a.iter() a.iter()
.map(|x| convert_json_value_to_nu_value(x)) .map(|x| convert_json_value_to_nu_value(x).spanned_unknown())
.collect(), .collect(),
), ),
serde_hjson::Value::Object(o) => { serde_hjson::Value::Object(o) => {
@ -35,9 +35,9 @@ pub fn from_json(args: CommandArgs) -> Result<OutputStream, ShellError> {
let span = args.name_span; let span = args.name_span;
Ok(out Ok(out
.values .values
.map(move |a| match a { .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) {
Ok(x) => ReturnSuccess::value(x), Ok(x) => ReturnSuccess::value(x.spanned(a.span)),
Err(_) => Err(ShellError::maybe_labeled_error( Err(_) => Err(ShellError::maybe_labeled_error(
"Could not parse as JSON", "Could not parse as JSON",
"piped data failed JSON parse", "piped data failed JSON parse",

View File

@ -10,7 +10,7 @@ fn convert_toml_value_to_nu_value(v: &toml::Value) -> Value {
toml::Value::String(s) => Value::Primitive(Primitive::String(String::from(s))), toml::Value::String(s) => Value::Primitive(Primitive::String(String::from(s))),
toml::Value::Array(a) => Value::List( toml::Value::Array(a) => Value::List(
a.iter() a.iter()
.map(|x| convert_toml_value_to_nu_value(x)) .map(|x| convert_toml_value_to_nu_value(x).spanned_unknown())
.collect(), .collect(),
), ),
toml::Value::Datetime(dt) => Value::Primitive(Primitive::String(dt.to_string())), toml::Value::Datetime(dt) => Value::Primitive(Primitive::String(dt.to_string())),
@ -34,9 +34,9 @@ pub fn from_toml(args: CommandArgs) -> Result<OutputStream, ShellError> {
let span = args.name_span; let span = args.name_span;
Ok(out Ok(out
.values .values
.map(move |a| match a { .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) {
Ok(x) => ReturnSuccess::value(x), Ok(x) => ReturnSuccess::value(x.spanned(a.span)),
Err(_) => Err(ShellError::maybe_labeled_error( Err(_) => Err(ShellError::maybe_labeled_error(
"Could not parse as TOML", "Could not parse as TOML",
"piped data failed TOML parse", "piped data failed TOML parse",

View File

@ -10,7 +10,7 @@ fn from_node_to_value<'a, 'd>(n: &roxmltree::Node<'a, 'd>) -> Value {
children_values.push(from_node_to_value(&c)); children_values.push(from_node_to_value(&c));
} }
let children_values: Vec<Value> = children_values let children_values: Vec<Spanned<Value>> = children_values
.into_iter() .into_iter()
.filter(|x| match x { .filter(|x| match x {
Value::Primitive(Primitive::String(f)) => { Value::Primitive(Primitive::String(f)) => {
@ -22,6 +22,7 @@ fn from_node_to_value<'a, 'd>(n: &roxmltree::Node<'a, 'd>) -> Value {
} }
_ => true, _ => true,
}) })
.map(|v| v.spanned_unknown())
.collect(); .collect();
let mut collected = Dictionary::default(); let mut collected = Dictionary::default();
@ -53,9 +54,9 @@ pub fn from_xml(args: CommandArgs) -> Result<OutputStream, ShellError> {
let span = args.name_span; let span = args.name_span;
Ok(out Ok(out
.values .values
.map(move |a| match a { .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) {
Ok(x) => ReturnSuccess::value(x), Ok(x) => ReturnSuccess::value(x.spanned(a.span)),
Err(_) => Err(ShellError::maybe_labeled_error( Err(_) => Err(ShellError::maybe_labeled_error(
"Could not parse as XML", "Could not parse as XML",
"piped data failed XML parse", "piped data failed XML parse",

View File

@ -14,7 +14,7 @@ fn convert_yaml_value_to_nu_value(v: &serde_yaml::Value) -> Value {
serde_yaml::Value::String(s) => Value::string(s), serde_yaml::Value::String(s) => Value::string(s),
serde_yaml::Value::Sequence(a) => Value::List( serde_yaml::Value::Sequence(a) => Value::List(
a.iter() a.iter()
.map(|x| convert_yaml_value_to_nu_value(x)) .map(|x| convert_yaml_value_to_nu_value(x).spanned_unknown())
.collect(), .collect(),
), ),
serde_yaml::Value::Mapping(t) => { serde_yaml::Value::Mapping(t) => {
@ -44,9 +44,9 @@ pub fn from_yaml(args: CommandArgs) -> Result<OutputStream, ShellError> {
let span = args.name_span; let span = args.name_span;
Ok(out Ok(out
.values .values
.map(move |a| match a { .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) {
Ok(x) => ReturnSuccess::value(x), Ok(x) => ReturnSuccess::value(x.spanned(a.span)),
Err(_) => Err(ShellError::maybe_labeled_error( Err(_) => Err(ShellError::maybe_labeled_error(
"Could not parse as YAML", "Could not parse as YAML",
"piped data failed YAML parse", "piped data failed YAML parse",

View File

@ -3,7 +3,7 @@ use crate::object::Value;
use crate::parser::Span; use crate::parser::Span;
use crate::prelude::*; use crate::prelude::*;
fn get_member(path: &str, span: Span, obj: &Value) -> Result<Value, ShellError> { fn get_member(path: &str, span: Span, obj: &Spanned<Value>) -> Result<Spanned<Value>, ShellError> {
let mut current = obj; let mut current = obj;
for p in path.split(".") { for p in path.split(".") {
match current.get_data_by_key(p) { match current.get_data_by_key(p) {
@ -18,7 +18,7 @@ fn get_member(path: &str, span: Span, obj: &Value) -> Result<Value, ShellError>
} }
} }
Ok(current.copy()) Ok(current.clone())
} }
pub fn get(args: CommandArgs) -> Result<OutputStream, ShellError> { pub fn get(args: CommandArgs) -> Result<OutputStream, ShellError> {
@ -56,12 +56,15 @@ pub fn get(args: CommandArgs) -> Result<OutputStream, ShellError> {
let mut result = VecDeque::new(); let mut result = VecDeque::new();
for field in &fields { for field in &fields {
match get_member(&field.0, field.1, &item) { match get_member(&field.0, field.1, &item) {
Ok(Value::List(l)) => { Ok(Spanned {
item: Value::List(l),
..
}) => {
for item in l { for item in l {
result.push_back(ReturnSuccess::value(item.copy())); result.push_back(ReturnSuccess::value(item.clone()));
} }
} }
Ok(x) => result.push_back(ReturnSuccess::value(x.copy())), Ok(x) => result.push_back(ReturnSuccess::value(x.clone())),
Err(_) => {} Err(_) => {}
} }
} }

View File

@ -11,7 +11,7 @@ pub fn lines(args: CommandArgs) -> Result<OutputStream, ShellError> {
let stream = input let stream = input
.values .values
.map(move |v| match v { .map(move |v| match v.item {
Value::Primitive(Primitive::String(s)) => { Value::Primitive(Primitive::String(s)) => {
let split_result: Vec<_> = s.lines().filter(|s| s.trim() != "").collect(); let split_result: Vec<_> = s.lines().filter(|s| s.trim() != "").collect();
@ -19,9 +19,9 @@ pub fn lines(args: CommandArgs) -> Result<OutputStream, ShellError> {
let mut result = VecDeque::new(); let mut result = VecDeque::new();
for s in split_result { for s in split_result {
result.push_back(ReturnSuccess::value(Value::Primitive(Primitive::String( result.push_back(ReturnSuccess::value(
s.into(), Value::Primitive(Primitive::String(s.into())).spanned_unknown(),
)))); ));
} }
result result
} }

View File

@ -18,7 +18,7 @@ pub fn ls(args: CommandArgs) -> Result<OutputStream, ShellError> {
_ => {} _ => {}
} }
match obj { match obj.item {
Value::Filesystem => { Value::Filesystem => {
let entries = std::fs::read_dir(&full_path); let entries = std::fs::read_dir(&full_path);
@ -45,7 +45,7 @@ pub fn ls(args: CommandArgs) -> Result<OutputStream, ShellError> {
for entry in entries { for entry in entries {
let value = Value::Object(dir_entry_dict(&entry?)?); let value = Value::Object(dir_entry_dict(&entry?)?);
shell_entries.push_back(ReturnSuccess::value(value)) shell_entries.push_back(ReturnSuccess::value(value.spanned_unknown()))
} }
Ok(shell_entries.to_output_stream()) Ok(shell_entries.to_output_stream())
} }
@ -125,9 +125,12 @@ pub fn ls(args: CommandArgs) -> Result<OutputStream, ShellError> {
} }
} }
match viewed { match viewed {
Value::List(l) => { Spanned {
item: Value::List(l),
..
} => {
for item in l { for item in l {
entries.push_back(ReturnSuccess::value(item.copy())); entries.push_back(ReturnSuccess::value(item.clone()));
} }
} }
x => { x => {

View File

@ -49,7 +49,7 @@ macro_rules! command {
positional: vec![$($mandatory_positional)*], positional: vec![$($mandatory_positional)*],
rest_positional: false, rest_positional: false,
named: { named: {
use $crate::parser::registry::{NamedType, NamedValue}; use $crate::parser::registry::NamedType;
#[allow(unused_mut)] #[allow(unused_mut)]
let mut named: indexmap::IndexMap<String, NamedType> = indexmap::IndexMap::new(); let mut named: indexmap::IndexMap<String, NamedType> = indexmap::IndexMap::new();
@ -261,10 +261,10 @@ macro_rules! command {
Extract { Extract {
$($extract:tt)* { $($extract:tt)* {
use std::convert::TryInto; use $crate::object::types::ExtractType;
let value = $args.expect_nth($($positional_count)*)?; let value = $args.expect_nth($($positional_count)*)?;
let value = $param_kind.check(value)?; // let value = $param_kind.check(value)?;
value.extract() $param_kind::extract(value)?
} }
} }
); );

View File

@ -21,7 +21,7 @@ command! {
let full_path = PathBuf::from(cwd); let full_path = PathBuf::from(cwd);
let (file_extension, contents) = match &args.expect_nth(0)?.item { let (file_extension, contents, contents_span) = match &args.expect_nth(0)?.item {
Value::Primitive(Primitive::String(s)) => fetch(&full_path, s, args.expect_nth(0)?.span)?, Value::Primitive(Primitive::String(s)) => fetch(&full_path, s, args.expect_nth(0)?.span)?,
_ => { _ => {
return Err(ShellError::labeled_error( return Err(ShellError::labeled_error(
@ -64,6 +64,7 @@ command! {
stream.push_back(ReturnSuccess::value(parse_as_value( stream.push_back(ReturnSuccess::value(parse_as_value(
file_extension, file_extension,
contents, contents,
contents_span,
span, span,
)?)); )?));
@ -75,7 +76,7 @@ pub fn fetch(
cwd: &PathBuf, cwd: &PathBuf,
location: &str, location: &str,
span: Span, span: Span,
) -> Result<(Option<String>, String), ShellError> { ) -> Result<(Option<String>, String, Span), ShellError> {
let mut cwd = cwd.clone(); let mut cwd = cwd.clone();
if location.starts_with("http:") || location.starts_with("https:") { if location.starts_with("http:") || location.starts_with("https:") {
let response = reqwest::get(location); let response = reqwest::get(location);
@ -106,7 +107,7 @@ pub fn fetch(
None => path_extension, None => path_extension,
}; };
Ok((extension, Value::string(s))) Ok((extension, s, span))
} }
Err(_) => { Err(_) => {
return Err(ShellError::labeled_error( return Err(ShellError::labeled_error(
@ -131,7 +132,8 @@ pub fn fetch(
Ok(s) => Ok(( Ok(s) => Ok((
cwd.extension() cwd.extension()
.map(|name| name.to_string_lossy().to_string()), .map(|name| name.to_string_lossy().to_string()),
Value::string(s), s,
span,
)), )),
Err(_) => Ok((None, Value::Binary(bytes))), Err(_) => Ok((None, Value::Binary(bytes))),
}, },
@ -149,10 +151,12 @@ pub fn fetch(
pub fn parse_as_value( pub fn parse_as_value(
extension: Option<String>, extension: Option<String>,
contents: String, contents: String,
contents_span: Span,
name_span: Option<Span>, name_span: Option<Span>,
) -> Result<Value, ShellError> { ) -> Result<Spanned<Value>, ShellError> {
match extension { match extension {
Some(x) if x == "toml" => crate::commands::from_toml::from_toml_string_to_value(contents) Some(x) if x == "toml" => crate::commands::from_toml::from_toml_string_to_value(contents)
.map(|c| c.spanned(contents_span))
.map_err(move |_| { .map_err(move |_| {
ShellError::maybe_labeled_error( ShellError::maybe_labeled_error(
"Could not open as TOML", "Could not open as TOML",
@ -161,6 +165,7 @@ pub fn parse_as_value(
) )
}), }),
Some(x) if x == "json" => crate::commands::from_json::from_json_string_to_value(contents) Some(x) if x == "json" => crate::commands::from_json::from_json_string_to_value(contents)
.map(|c| c.spanned(contents_span))
.map_err(move |_| { .map_err(move |_| {
ShellError::maybe_labeled_error( ShellError::maybe_labeled_error(
"Could not open as JSON", "Could not open as JSON",
@ -169,6 +174,7 @@ pub fn parse_as_value(
) )
}), }),
Some(x) if x == "ini" => crate::commands::from_ini::from_ini_string_to_value(contents) Some(x) if x == "ini" => crate::commands::from_ini::from_ini_string_to_value(contents)
.map(|c| c.spanned(contents_span))
.map_err(move |_| { .map_err(move |_| {
ShellError::maybe_labeled_error( ShellError::maybe_labeled_error(
"Could not open as INI", "Could not open as INI",
@ -177,6 +183,7 @@ pub fn parse_as_value(
) )
}), }),
Some(x) if x == "xml" => crate::commands::from_xml::from_xml_string_to_value(contents) Some(x) if x == "xml" => crate::commands::from_xml::from_xml_string_to_value(contents)
.map(|c| c.spanned(contents_span))
.map_err(move |_| { .map_err(move |_| {
ShellError::maybe_labeled_error( ShellError::maybe_labeled_error(
"Could not open as XML", "Could not open as XML",
@ -185,6 +192,7 @@ pub fn parse_as_value(
) )
}), }),
Some(x) if x == "yml" => crate::commands::from_yaml::from_yaml_string_to_value(contents) Some(x) if x == "yml" => crate::commands::from_yaml::from_yaml_string_to_value(contents)
.map(|c| c.spanned(contents_span))
.map_err(move |_| { .map_err(move |_| {
ShellError::maybe_labeled_error( ShellError::maybe_labeled_error(
"Could not open as YAML", "Could not open as YAML",
@ -193,6 +201,7 @@ pub fn parse_as_value(
) )
}), }),
Some(x) if x == "yaml" => crate::commands::from_yaml::from_yaml_string_to_value(contents) Some(x) if x == "yaml" => crate::commands::from_yaml::from_yaml_string_to_value(contents)
.map(|c| c.spanned(contents_span))
.map_err(move |_| { .map_err(move |_| {
ShellError::maybe_labeled_error( ShellError::maybe_labeled_error(
"Could not open as YAML", "Could not open as YAML",
@ -200,6 +209,6 @@ pub fn parse_as_value(
name_span, name_span,
) )
}), }),
_ => Ok(Value::string(contents)), _ => Ok(Value::string(contents).spanned(contents_span)),
} }
} }

View File

@ -14,11 +14,11 @@ pub fn pick(args: CommandArgs) -> Result<OutputStream, ShellError> {
let fields: Result<Vec<String>, _> = args.positional_iter().map(|a| a.as_string()).collect(); let fields: Result<Vec<String>, _> = args.positional_iter().map(|a| a.as_string()).collect();
let fields = fields?; let fields = fields?;
let input = args.input;
let objects = args let objects = input
.input
.values .values
.map(move |item| Value::Object(select_fields(&item, &fields))); .map(move |value| Value::Object(select_fields(&value.item, &fields)).spanned(value.span));
Ok(objects.from_input_stream()) Ok(objects.from_input_stream())
} }

View File

@ -50,14 +50,17 @@ pub fn filter_plugin(path: String, args: CommandArgs) -> Result<OutputStream, Sh
stdin.write(format!("{}\n", request_raw).as_bytes())?; stdin.write(format!("{}\n", request_raw).as_bytes())?;
} }
let mut eos = VecDeque::new(); let mut eos: VecDeque<Spanned<Value>> = VecDeque::new();
eos.push_back(Value::Primitive(Primitive::EndOfStream)); eos.push_back(Value::Primitive(Primitive::EndOfStream).spanned_unknown());
let stream = args let stream = args
.input .input
.chain(eos) .chain(eos)
.map(move |v| match v { .map(move |v| match v {
Value::Primitive(Primitive::EndOfStream) => { Spanned {
item: Value::Primitive(Primitive::EndOfStream),
..
} => {
let stdin = child.stdin.as_mut().expect("Failed to open stdin"); let stdin = child.stdin.as_mut().expect("Failed to open stdin");
let stdout = child.stdout.as_mut().expect("Failed to open stdout"); let stdout = child.stdout.as_mut().expect("Failed to open stdout");

View File

@ -4,14 +4,14 @@ use crate::object::Value;
use crate::prelude::*; use crate::prelude::*;
use sysinfo::{RefreshKind, SystemExt}; use sysinfo::{RefreshKind, SystemExt};
pub fn ps(_args: CommandArgs) -> Result<OutputStream, ShellError> { pub fn ps(args: CommandArgs) -> Result<OutputStream, ShellError> {
let mut system = sysinfo::System::new_with_specifics(RefreshKind::new().with_processes()); let mut system = sysinfo::System::new_with_specifics(RefreshKind::new().with_processes());
system.refresh_processes(); system.refresh_processes();
let list = system.get_process_list(); let list = system.get_process_list();
let list = list let list = list
.into_iter() .into_iter()
.map(|(_, process)| Value::Object(process_dict(process))) .map(|(item, process)| Value::Object(process_dict(process)).spanned(args.name_span))
.collect::<VecDeque<_>>(); .collect::<VecDeque<_>>();
Ok(list.from_input_stream()) Ok(list.from_input_stream())

View File

@ -18,7 +18,7 @@ pub fn reject(args: CommandArgs) -> Result<OutputStream, ShellError> {
let stream = args let stream = args
.input .input
.values .values
.map(move |item| Value::Object(reject_fields(&item, &fields))); .map(move |item| Value::Object(reject_fields(&item, &fields)).spanned(args.name_span));
Ok(stream.from_input_stream()) Ok(stream.from_input_stream())
} }

View File

@ -24,20 +24,20 @@ pub fn size(args: CommandArgs) -> Result<OutputStream, ShellError> {
let mut contents = String::new(); let mut contents = String::new();
let mut list = VecDeque::new(); let mut list: VecDeque<ReturnValue> = VecDeque::new();
for name in args.positional_iter() { for spanned_name in args.positional_iter() {
let name = name.as_string()?; let name = spanned_name.as_string()?;
let path = cwd.join(&name); let path = cwd.join(&name);
let mut file = File::open(path)?; let mut file = File::open(path)?;
file.read_to_string(&mut contents)?; file.read_to_string(&mut contents)?;
list.push_back(count(&name, &contents)); list.push_back(count(&name, &contents).spanned(spanned_name).into());
contents.clear(); contents.clear();
} }
Ok(list.to_output_stream()) Ok(list.to_output_stream())
} }
fn count(name: &str, contents: &str) -> ReturnValue { fn count(name: &str, contents: &str) -> Value {
let mut lines: i64 = 0; let mut lines: i64 = 0;
let mut words: i64 = 0; let mut words: i64 = 0;
let mut chars: i64 = 0; let mut chars: i64 = 0;
@ -69,5 +69,5 @@ fn count(name: &str, contents: &str) -> ReturnValue {
dict.add("chars", Value::int(chars)); dict.add("chars", Value::int(chars));
dict.add("max length", Value::int(bytes)); dict.add("max length", Value::int(bytes));
ReturnSuccess::value(Value::Object(dict)) Value::Object(dict)
} }

View File

@ -11,8 +11,8 @@ pub fn sort_by(args: CommandArgs) -> Result<OutputStream, ShellError> {
vec.sort_by_key(|item| { vec.sort_by_key(|item| {
fields fields
.iter() .iter()
.map(|f| item.get_data_by_key(f).map(|i| i.copy())) .map(|f| item.get_data_by_key(f).map(|i| i.clone()))
.collect::<Vec<Option<Value>>>() .collect::<Vec<Option<Spanned<Value>>>>()
}); });
vec.into_iter().collect::<VecDeque<_>>() vec.into_iter().collect::<VecDeque<_>>()

View File

@ -21,7 +21,7 @@ pub fn split_column(args: CommandArgs) -> Result<OutputStream, ShellError> {
Ok(input Ok(input
.values .values
.map(move |v| match v { .map(move |v| match v.item {
Value::Primitive(Primitive::String(s)) => { Value::Primitive(Primitive::String(s)) => {
let splitter = positional[0].as_string().unwrap().replace("\\n", "\n"); let splitter = positional[0].as_string().unwrap().replace("\\n", "\n");
trace!("splitting with {:?}", splitter); trace!("splitting with {:?}", splitter);
@ -40,7 +40,7 @@ pub fn split_column(args: CommandArgs) -> Result<OutputStream, ShellError> {
for (&k, v) in split_result.iter().zip(gen_columns.iter()) { for (&k, v) in split_result.iter().zip(gen_columns.iter()) {
dict.add(v.clone(), Value::Primitive(Primitive::String(k.into()))); dict.add(v.clone(), Value::Primitive(Primitive::String(k.into())));
} }
ReturnSuccess::value(Value::Object(dict)) ReturnSuccess::value(Value::Object(dict).spanned(v.span))
} else if split_result.len() == (positional.len() - 1) { } else if split_result.len() == (positional.len() - 1) {
let mut dict = crate::object::Dictionary::default(); let mut dict = crate::object::Dictionary::default();
for (&k, v) in split_result.iter().zip(positional.iter().skip(1)) { for (&k, v) in split_result.iter().zip(positional.iter().skip(1)) {
@ -49,7 +49,7 @@ pub fn split_column(args: CommandArgs) -> Result<OutputStream, ShellError> {
Value::Primitive(Primitive::String(k.into())), Value::Primitive(Primitive::String(k.into())),
); );
} }
ReturnSuccess::value(Value::Object(dict)) ReturnSuccess::value(Value::Object(dict).spanned(v.span))
} else { } else {
let mut dict = crate::object::Dictionary::default(); let mut dict = crate::object::Dictionary::default();
for k in positional.iter().skip(1) { for k in positional.iter().skip(1) {
@ -58,7 +58,7 @@ pub fn split_column(args: CommandArgs) -> Result<OutputStream, ShellError> {
Value::Primitive(Primitive::String("".into())), Value::Primitive(Primitive::String("".into())),
); );
} }
ReturnSuccess::value(Value::Object(dict)) ReturnSuccess::value(Value::Object(dict).spanned(v.span))
} }
} }
_ => Err(ShellError::maybe_labeled_error( _ => Err(ShellError::maybe_labeled_error(

View File

@ -22,7 +22,7 @@ pub fn split_row(args: CommandArgs) -> Result<OutputStream, ShellError> {
let stream = input let stream = input
.values .values
.map(move |v| match v { .map(move |v| match v.item {
Value::Primitive(Primitive::String(s)) => { Value::Primitive(Primitive::String(s)) => {
let splitter = positional[0].as_string().unwrap().replace("\\n", "\n"); let splitter = positional[0].as_string().unwrap().replace("\\n", "\n");
trace!("splitting with {:?}", splitter); trace!("splitting with {:?}", splitter);
@ -32,9 +32,9 @@ pub fn split_row(args: CommandArgs) -> Result<OutputStream, ShellError> {
let mut result = VecDeque::new(); let mut result = VecDeque::new();
for s in split_result { for s in split_result {
result.push_back(ReturnSuccess::value(Value::Primitive(Primitive::String( result.push_back(ReturnSuccess::value(
s.into(), Value::Primitive(Primitive::String(s.into())).spanned(v.span),
)))); ));
} }
result result
} }

View File

@ -1,95 +1,53 @@
use crate::errors::ShellError; use crate::errors::ShellError;
use crate::object::base::OF64; use crate::object::base::OF64;
use crate::object::Dictionary; use crate::object::SpannedDictBuilder;
use crate::object::{Primitive, Value}; use crate::object::{Primitive, Value};
use crate::prelude::*; use crate::prelude::*;
use log::trace;
use sys_info::*; use sys_info::*;
use sysinfo::{ComponentExt, DiskExt, NetworkExt, RefreshKind, SystemExt}; use sysinfo::{ComponentExt, DiskExt, NetworkExt, RefreshKind, SystemExt};
pub fn sysinfo(_args: CommandArgs) -> Result<OutputStream, ShellError> { pub fn sysinfo(args: CommandArgs) -> Result<OutputStream, ShellError> {
let mut idx = indexmap::IndexMap::new(); let mut idx = SpannedDictBuilder::new(args.name_span);
if let (Ok(name), Ok(version)) = (os_type(), os_release()) { if let (Ok(name), Ok(version)) = (os_type(), os_release()) {
let mut os_idx = indexmap::IndexMap::new(); let mut os_idx = SpannedDictBuilder::new(args.name_span);
os_idx.insert( os_idx.insert("name", Primitive::String(name));
"name".to_string(), os_idx.insert("version", Primitive::String(version));
Value::Primitive(Primitive::String(name)),
);
os_idx.insert(
"version".to_string(),
Value::Primitive(Primitive::String(version)),
);
idx.insert("os".to_string(), Value::Object(Dictionary::from(os_idx))); idx.insert_spanned("os", os_idx.into_spanned_value());
} }
if let (Ok(num_cpu), Ok(cpu_speed)) = (cpu_num(), cpu_speed()) { if let (Ok(num_cpu), Ok(cpu_speed)) = (cpu_num(), cpu_speed()) {
let mut cpu_idx = indexmap::IndexMap::new(); let mut cpu_idx = SpannedDictBuilder::new(args.name_span);
cpu_idx.insert( cpu_idx.insert("num", Primitive::Int(num_cpu as i64));
"num".to_string(), cpu_idx.insert("speed", Primitive::Int(cpu_speed as i64));
Value::Primitive(Primitive::Int(num_cpu as i64)),
);
cpu_idx.insert(
"speed".to_string(),
Value::Primitive(Primitive::Int(cpu_speed as i64)),
);
idx.insert("cpu".to_string(), Value::Object(Dictionary::from(cpu_idx))); idx.insert_spanned("cpu", cpu_idx);
} }
if let Ok(x) = loadavg() { if let Ok(x) = loadavg() {
let mut load_idx = indexmap::IndexMap::new(); let mut load_idx = SpannedDictBuilder::new(args.name_span);
load_idx.insert(
"1min".to_string(),
Value::Primitive(Primitive::Float(OF64::from(x.one))),
);
load_idx.insert(
"5min".to_string(),
Value::Primitive(Primitive::Float(OF64::from(x.five))),
);
load_idx.insert(
"15min".to_string(),
Value::Primitive(Primitive::Float(OF64::from(x.fifteen))),
);
idx.insert( load_idx.insert("1min", Primitive::Float(OF64::from(x.one)));
"load avg".to_string(), load_idx.insert("5min", Primitive::Float(OF64::from(x.five)));
Value::Object(Dictionary::from(load_idx)), load_idx.insert("15min", Primitive::Float(OF64::from(x.fifteen)));
);
idx.insert_spanned("load avg", load_idx);
} }
if let Ok(x) = mem_info() { if let Ok(x) = mem_info() {
let mut mem_idx = indexmap::IndexMap::new(); let mut mem_idx = SpannedDictBuilder::new(args.name_span);
mem_idx.insert(
"total".to_string(),
Value::Primitive(Primitive::Bytes(x.total as u64 * 1024)),
);
mem_idx.insert(
"free".to_string(),
Value::Primitive(Primitive::Bytes(x.free as u64 * 1024)),
);
mem_idx.insert(
"avail".to_string(),
Value::Primitive(Primitive::Bytes(x.avail as u64 * 1024)),
);
mem_idx.insert(
"buffers".to_string(),
Value::Primitive(Primitive::Bytes(x.buffers as u64 * 1024)),
);
mem_idx.insert(
"cached".to_string(),
Value::Primitive(Primitive::Bytes(x.cached as u64 * 1024)),
);
mem_idx.insert(
"swap total".to_string(),
Value::Primitive(Primitive::Bytes(x.swap_total as u64 * 1024)),
);
mem_idx.insert(
"swap free".to_string(),
Value::Primitive(Primitive::Bytes(x.swap_free as u64 * 1024)),
);
idx.insert("mem".to_string(), Value::Object(Dictionary::from(mem_idx))); mem_idx.insert("total", Primitive::Bytes(x.total as u64 * 1024));
mem_idx.insert("free", Primitive::Bytes(x.free as u64 * 1024));
mem_idx.insert("avail", Primitive::Bytes(x.avail as u64 * 1024));
mem_idx.insert("buffers", Primitive::Bytes(x.buffers as u64 * 1024));
mem_idx.insert("cached", Primitive::Bytes(x.cached as u64 * 1024));
mem_idx.insert("swap total", Primitive::Bytes(x.swap_total as u64 * 1024));
mem_idx.insert("swap free", Primitive::Bytes(x.swap_free as u64 * 1024));
idx.insert_spanned("mem", mem_idx);
} }
/* /*
@ -107,57 +65,42 @@ pub fn sysinfo(_args: CommandArgs) -> Result<OutputStream, ShellError> {
*/ */
if let Ok(x) = hostname() { if let Ok(x) = hostname() {
idx.insert( idx.insert("hostname", Primitive::String(x));
"hostname".to_string(),
Value::Primitive(Primitive::String(x)),
);
} }
#[cfg(not(windows))] #[cfg(not(windows))]
{ {
if let Ok(x) = boottime() { if let Ok(x) = boottime() {
let mut boottime_idx = indexmap::IndexMap::new(); let mut boottime_idx = SpannedDictBuilder::new(args.name_span);
boottime_idx.insert( boottime_idx.insert("days", Primitive::Int(x.tv_sec / (24 * 3600)));
"days".to_string(), boottime_idx.insert("hours", Primitive::Int((x.tv_sec / 3600) % 24));
Value::Primitive(Primitive::Int(x.tv_sec / (24 * 3600))), boottime_idx.insert("mins", Primitive::Int((x.tv_sec / 60) % 60));
);
boottime_idx.insert(
"hours".to_string(),
Value::Primitive(Primitive::Int((x.tv_sec / 3600) % 24)),
);
boottime_idx.insert(
"mins".to_string(),
Value::Primitive(Primitive::Int((x.tv_sec / 60) % 60)),
);
idx.insert( idx.insert("uptime", boottime_idx);
"uptime".to_string(),
Value::Object(Dictionary::from(boottime_idx)),
);
} }
} }
let system = sysinfo::System::new_with_specifics(RefreshKind::everything().without_processes()); let system = sysinfo::System::new_with_specifics(RefreshKind::everything().without_processes());
let components_list = system.get_components_list(); let components_list = system.get_components_list();
if components_list.len() > 0 { if components_list.len() > 0 {
let mut v = vec![]; let mut v: Vec<Spanned<Value>> = vec![];
for component in components_list { for component in components_list {
let mut component_idx = indexmap::IndexMap::new(); let mut component_idx = SpannedDictBuilder::new(args.name_span);
component_idx.insert("name", Primitive::String(component.get_label().to_string()));
component_idx.insert( component_idx.insert(
"name".to_string(), "temp",
Value::string(component.get_label().to_string()), Primitive::Float(OF64::from(component.get_temperature() as f64)),
); );
component_idx.insert( component_idx.insert(
"temp".to_string(), "max",
Value::float(component.get_temperature() as f64), Primitive::Float(OF64::from(component.get_max() as f64)),
); );
component_idx.insert("max".to_string(), Value::float(component.get_max() as f64));
if let Some(critical) = component.get_critical() { if let Some(critical) = component.get_critical() {
component_idx.insert("critical".to_string(), Value::float(critical as f64)); component_idx.insert("critical", Primitive::Float(OF64::from(critical as f64)));
} }
v.push(Value::Object(Dictionary::from(component_idx))); v.push(component_idx.into());
} }
idx.insert("temps".to_string(), Value::List(v)); idx.insert("temps", Value::List(v));
} }
let disks = system.get_disks(); let disks = system.get_disks();
@ -165,38 +108,26 @@ pub fn sysinfo(_args: CommandArgs) -> Result<OutputStream, ShellError> {
let mut v = vec![]; let mut v = vec![];
for disk in disks { for disk in disks {
let mut disk_idx = indexmap::IndexMap::new(); let mut disk_idx = SpannedDictBuilder::new(args.name_span);
disk_idx.insert( disk_idx.insert("name", Value::string(disk.get_name().to_string_lossy()));
"name".to_string(), disk_idx.insert("available", Value::bytes(disk.get_available_space()));
Value::string(disk.get_name().to_string_lossy()), disk_idx.insert("total", Value::bytes(disk.get_total_space()));
); v.push(disk_idx.into());
disk_idx.insert(
"available".to_string(),
Value::bytes(disk.get_available_space()),
);
disk_idx.insert("total".to_string(), Value::bytes(disk.get_total_space()));
v.push(Value::Object(Dictionary::from(disk_idx)));
} }
idx.insert("disks".to_string(), Value::List(v)); idx.insert("disks", Value::List(v));
} }
let network = system.get_network(); let network = system.get_network();
let incoming = network.get_income(); let incoming = network.get_income();
let outgoing = network.get_outcome(); let outgoing = network.get_outcome();
let mut network_idx = indexmap::IndexMap::new(); let mut network_idx = SpannedDictBuilder::new(args.name_span);
network_idx.insert("incoming".to_string(), Value::bytes(incoming)); network_idx.insert("incoming", Value::bytes(incoming));
network_idx.insert("outgoing".to_string(), Value::bytes(outgoing)); network_idx.insert("outgoing", Value::bytes(outgoing));
idx.insert( idx.insert_spanned("network", network_idx);
"network".to_string(),
Value::Object(Dictionary::from(network_idx)),
);
// println!("{:#?}", system.get_network()); let mut stream = stream![idx.into_spanned_value()];
let mut stream = VecDeque::new();
stream.push_back(Value::Object(Dictionary::from(idx)));
Ok(stream.from_input_stream()) Ok(stream.from_input_stream())
} }

View File

@ -5,7 +5,7 @@ pub fn to_array(args: CommandArgs) -> Result<OutputStream, ShellError> {
let out = args.input.values.collect(); let out = args.input.values.collect();
Ok(out Ok(out
.map(|vec: Vec<_>| stream![Value::List(vec)]) .map(|vec: Vec<_>| stream![Value::List(vec).spanned_unknown()]) // TODO: args.input should have a span
.flatten_stream() .flatten_stream()
.from_input_stream()) .from_input_stream())
} }

View File

@ -45,15 +45,16 @@ pub fn to_json(args: CommandArgs) -> Result<OutputStream, ShellError> {
let out = args.input; let out = args.input;
let span = args.name_span; let span = args.name_span;
Ok(out Ok(out
.map( .values
move |a| match serde_json::to_string(&value_to_json_value(&a)) { .map(move |a| match serde_json::to_string(&a) {
Ok(x) => Ok(ReturnValue::Value(Value::Primitive(Primitive::String(x)))), Ok(x) => {
Err(_) => Err(ShellError::maybe_labeled_error( ReturnSuccess::value(Value::Primitive(Primitive::String(x)).spanned(args.name_span))
"Can not convert to JSON string", }
"can not convert piped data to JSON string", Err(_) => Err(ShellError::maybe_labeled_error(
span, "Can not convert to JSON string",
)), "can not convert piped data to JSON string",
}, span,
) )),
.boxed()) })
.to_output_stream())
} }

View File

@ -37,7 +37,9 @@ pub fn to_toml(args: CommandArgs) -> Result<OutputStream, ShellError> {
Ok(out Ok(out
.values .values
.map(move |a| match toml::to_string(&a) { .map(move |a| match toml::to_string(&a) {
Ok(x) => ReturnSuccess::value(Value::Primitive(Primitive::String(x))), Ok(x) => {
ReturnSuccess::value(Value::Primitive(Primitive::String(x)).spanned(args.name_span))
}
Err(_) => Err(ShellError::maybe_labeled_error( Err(_) => Err(ShellError::maybe_labeled_error(
"Can not convert to TOML string", "Can not convert to TOML string",
"can not convert piped data to TOML string", "can not convert piped data to TOML string",

View File

@ -10,15 +10,14 @@ pub fn trim(args: CommandArgs) -> Result<OutputStream, ShellError> {
Ok(input Ok(input
.values .values
.map(move |v| match v { .map(move |v| ReturnSuccess::value(String::check(&v)?.clone()))
Value::Primitive(Primitive::String(s)) => { // Value::Primitive(Primitive::String(s)) => {
ReturnSuccess::value(Value::Primitive(Primitive::String(s.trim().into()))) // ReturnSuccess::value(Value::Primitive(Primitive::String(s.trim().into())))
} // }
_ => Err(ShellError::maybe_labeled_error( // _ => Err(ShellError::maybe_labeled_error(
"Expected string values from pipeline", // "Expected string values from pipeline",
"expects strings from pipeline", // "expects strings from pipeline",
span, // span,
)), // )),
})
.to_output_stream()) .to_output_stream())
} }

View File

@ -1,5 +1,5 @@
use crate::errors::ShellError; use crate::errors::ShellError;
use crate::object::types::*; use crate::object::Block;
use crate::prelude::*; use crate::prelude::*;
use futures::future::ready; use futures::future::ready;
use log::trace; use log::trace;
@ -13,7 +13,7 @@ command! {
let return_value = match result { let return_value = match result {
Err(err) => Some(Err(err)), Err(err) => Some(Err(err)),
Ok(v) if v.is_true() => Some(Ok(ReturnSuccess::Value(item.copy()))), Ok(v) if v.is_true() => Some(Ok(ReturnSuccess::Value(item.clone()))),
_ => None, _ => None,
}; };

View File

@ -54,7 +54,7 @@ impl Context {
command: Arc<dyn Sink>, command: Arc<dyn Sink>,
name_span: Option<Span>, name_span: Option<Span>,
args: Args, args: Args,
input: Vec<Value>, input: Vec<Spanned<Value>>,
) -> Result<(), ShellError> { ) -> Result<(), ShellError> {
let command_args = SinkCommandArgs { let command_args = SinkCommandArgs {
ctx: self.clone(), ctx: self.clone(),

View File

@ -1,9 +1,10 @@
use crate::object::base::Value; use crate::object::base::Value;
use crate::prelude::*;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Environment { pub struct Environment {
crate obj: Value, crate obj: Spanned<Value>,
crate path: PathBuf, crate path: PathBuf,
} }
@ -12,7 +13,7 @@ impl Environment {
let path = std::env::current_dir()?; let path = std::env::current_dir()?;
Ok(Environment { Ok(Environment {
obj: Value::Filesystem, obj: Value::Filesystem.spanned_unknown(),
path, path,
}) })
} }
@ -21,7 +22,7 @@ impl Environment {
self.path.as_path() self.path.as_path()
} }
pub fn obj(&self) -> &Value { pub fn obj(&self) -> &Spanned<Value> {
&self.obj &self.obj
} }
} }

View File

@ -48,7 +48,7 @@ pub fn labelled(
) -> impl FnOnce(ShellError) -> ShellError + 'a { ) -> impl FnOnce(ShellError) -> ShellError + 'a {
let span = span.into(); let span = span.into();
move |error| ShellError::maybe_labeled_error(heading, span_message, span) move |_| ShellError::maybe_labeled_error(heading, span_message, span)
} }
#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Serialize, Deserialize)] #[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Serialize, Deserialize)]
@ -247,10 +247,6 @@ impl ShellError {
crate fn unexpected(title: impl Into<String>) -> ShellError { crate fn unexpected(title: impl Into<String>) -> ShellError {
ShellError::string(&format!("Unexpected: {}", title.into())) ShellError::string(&format!("Unexpected: {}", title.into()))
} }
crate fn copy_error(&self) -> ShellError {
self.clone()
}
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]

View File

@ -10,15 +10,15 @@ use indexmap::IndexMap;
#[derive(new)] #[derive(new)]
crate struct Scope { crate struct Scope {
it: Value, it: Spanned<Value>,
#[new(default)] #[new(default)]
vars: IndexMap<String, Value>, vars: IndexMap<String, Spanned<Value>>,
} }
impl Scope { impl Scope {
crate fn empty() -> Scope { crate fn empty() -> Scope {
Scope { Scope {
it: Value::nothing(), it: Value::nothing().spanned_unknown(),
vars: IndexMap::new(), vars: IndexMap::new(),
} }
} }
@ -64,8 +64,10 @@ crate fn evaluate_baseline_expr(
}) })
} }
Some(next) => { Some(next) => {
item = item = Spanned::from_item(
Spanned::from_item(next.clone(), (expr.span().start, name.span().end)) next.clone().item,
(expr.span().start, name.span().end),
)
} }
}; };
} }
@ -93,14 +95,11 @@ fn evaluate_reference(
source: &Text, source: &Text,
) -> Result<Spanned<Value>, ShellError> { ) -> Result<Spanned<Value>, ShellError> {
match name { match name {
hir::Variable::It(span) => Ok(Spanned::from_item(scope.it.copy(), span)), hir::Variable::It(span) => Ok(Spanned::from_item(scope.it.item, span)),
hir::Variable::Other(span) => Ok(Spanned::from_item( hir::Variable::Other(span) => Ok(scope
scope .vars
.vars .get(span.slice(source))
.get(span.slice(source)) .map(|v| v.clone())
.map(|v| v.copy()) .unwrap_or_else(|| Value::nothing().spanned(span))),
.unwrap_or_else(|| Value::nothing()),
span,
)),
} }
} }

View File

@ -13,7 +13,7 @@ pub struct TableView {
} }
impl TableView { impl TableView {
fn merge_descriptors(values: &[Value]) -> Vec<String> { fn merge_descriptors(values: &[Spanned<Value>]) -> Vec<String> {
let mut ret = vec![]; let mut ret = vec![];
for value in values { for value in values {
for desc in value.data_descriptors() { for desc in value.data_descriptors() {
@ -25,7 +25,7 @@ impl TableView {
ret ret
} }
pub fn from_list(values: &[Value]) -> Option<TableView> { pub fn from_list(values: &[Spanned<Value>]) -> Option<TableView> {
if values.len() == 0 { if values.len() == 0 {
return None; return None;
} }

View File

@ -12,7 +12,7 @@ pub struct VTableView {
} }
impl VTableView { impl VTableView {
pub fn from_list(values: &[Value]) -> Option<VTableView> { pub fn from_list(values: &[Spanned<Value>]) -> Option<VTableView> {
if values.len() == 0 { if values.len() == 0 {
return None; return None;
} }

View File

@ -2,9 +2,10 @@ crate mod base;
crate mod config; crate mod config;
crate mod dict; crate mod dict;
crate mod files; crate mod files;
crate mod into;
crate mod process; crate mod process;
crate mod types; crate mod types;
crate use base::{Primitive, Value}; crate use base::{Block, Primitive, Switch, Value};
crate use dict::Dictionary; crate use dict::{Dictionary, SpannedDictBuilder};
crate use files::dir_entry_dict; crate use files::dir_entry_dict;

View File

@ -153,8 +153,8 @@ impl Deserialize<'de> for Block {
} }
impl Block { impl Block {
pub fn invoke(&self, value: &Value) -> Result<Spanned<Value>, ShellError> { pub fn invoke(&self, value: &Spanned<Value>) -> Result<Spanned<Value>, ShellError> {
let scope = Scope::new(value.copy()); let scope = Scope::new(value.clone());
if self.expressions.len() == 0 { if self.expressions.len() == 0 {
return Ok(Spanned::from_item(Value::nothing(), self.span)); return Ok(Spanned::from_item(Value::nothing(), self.span));
@ -174,20 +174,19 @@ impl Block {
pub enum Value { pub enum Value {
Primitive(Primitive), Primitive(Primitive),
Object(crate::object::Dictionary), Object(crate::object::Dictionary),
List(Vec<Value>),
Binary(Vec<u8>), Binary(Vec<u8>),
List(Vec<Spanned<Value>>),
#[allow(unused)] #[allow(unused)]
Block(Block), Block(Block),
Filesystem, Filesystem,
} }
pub fn debug_list(values: &'a Vec<Value>) -> ValuesDebug<'a> { pub fn debug_list(values: &'a Vec<Spanned<Value>>) -> ValuesDebug<'a> {
ValuesDebug { values } ValuesDebug { values }
} }
pub struct ValuesDebug<'a> { pub struct ValuesDebug<'a> {
values: &'a Vec<Value>, values: &'a Vec<Spanned<Value>>,
} }
impl fmt::Debug for ValuesDebug<'a> { impl fmt::Debug for ValuesDebug<'a> {
@ -199,12 +198,12 @@ impl fmt::Debug for ValuesDebug<'a> {
} }
pub struct ValueDebug<'a> { pub struct ValueDebug<'a> {
value: &'a Value, value: &'a Spanned<Value>,
} }
impl fmt::Debug for ValueDebug<'a> { impl fmt::Debug for ValueDebug<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.value { match self.value.item() {
Value::Primitive(p) => p.debug(f), Value::Primitive(p) => p.debug(f),
Value::Object(o) => o.debug(f), Value::Object(o) => o.debug(f),
Value::List(l) => debug_list(l).fmt(f), Value::List(l) => debug_list(l).fmt(f),
@ -281,6 +280,12 @@ impl std::convert::TryFrom<Option<&'a Spanned<Value>>> for Switch {
} }
} }
impl Spanned<Value> {
crate fn debug(&'a self) -> ValueDebug<'a> {
ValueDebug { value: self }
}
}
impl Value { impl Value {
crate fn type_name(&self) -> String { crate fn type_name(&self) -> String {
match self { match self {
@ -314,13 +319,16 @@ impl Value {
} }
} }
crate fn get_data_by_key(&'a self, name: &str) -> Option<&Value> { crate fn get_data_by_key(&'a self, name: &str) -> Option<&Spanned<Value>> {
match self { match self {
Value::Object(o) => o.get_data_by_key(name), Value::Object(o) => o.get_data_by_key(name),
Value::List(l) => { Value::List(l) => {
for item in l { for item in l {
match item { match item {
Value::Object(o) => match o.get_data_by_key(name) { Spanned {
item: Value::Object(o),
..
} => match o.get_data_by_key(name) {
Some(v) => return Some(v), Some(v) => return Some(v),
None => {} None => {}
}, },
@ -333,7 +341,7 @@ impl Value {
} }
} }
crate fn get_data_by_index(&'a self, idx: usize) -> Option<&Value> { crate fn get_data_by_index(&'a self, idx: usize) -> Option<&Spanned<Value>> {
match self { match self {
Value::List(l) => l.iter().nth(idx), Value::List(l) => l.iter().nth(idx),
_ => None, _ => None,
@ -352,20 +360,6 @@ impl Value {
} }
} }
crate fn copy(&self) -> Value {
match self {
Value::Primitive(p) => Value::Primitive(p.clone()),
Value::Object(o) => Value::Object(o.copy_dict()),
Value::Block(b) => Value::Block(b.clone()),
Value::List(l) => {
let list = l.iter().map(|i| i.copy()).collect();
Value::List(list)
}
Value::Filesystem => Value::Filesystem,
Value::Binary(b) => Value::Binary(b.clone()),
}
}
crate fn format_leaf(&self, desc: Option<&String>) -> String { crate fn format_leaf(&self, desc: Option<&String>) -> String {
match self { match self {
Value::Primitive(p) => p.format(desc), Value::Primitive(p) => p.format(desc),
@ -417,7 +411,7 @@ impl Value {
} }
} }
crate fn as_pair(&self) -> Result<(Value, Value), ShellError> { crate fn as_pair(&self) -> Result<(Spanned<Value>, Spanned<Value>), ShellError> {
match self { match self {
Value::List(list) if list.len() == 2 => Ok((list[0].clone(), list[1].clone())), Value::List(list) if list.len() == 2 => Ok((list[0].clone(), list[1].clone())),
other => Err(ShellError::string(format!( other => Err(ShellError::string(format!(
@ -509,11 +503,6 @@ impl Value {
pub fn nothing() -> Value { pub fn nothing() -> Value {
Value::Primitive(Primitive::Nothing) Value::Primitive(Primitive::Nothing)
} }
#[allow(unused)]
pub fn list(values: impl Into<Vec<Value>>) -> Value {
Value::List(values.into())
}
} }
crate fn select_fields(obj: &Value, fields: &[String]) -> crate::object::Dictionary { crate fn select_fields(obj: &Value, fields: &[String]) -> crate::object::Dictionary {
@ -522,9 +511,9 @@ crate fn select_fields(obj: &Value, fields: &[String]) -> crate::object::Diction
let descs = obj.data_descriptors(); let descs = obj.data_descriptors();
for field in fields { for field in fields {
match descs.iter().find(|d| *d == field) { match descs.iter().find(|d| d.name.is_string(field)) {
None => out.add(field, Value::nothing()), None => out.add(field, Value::nothing()),
Some(desc) => out.add(desc.clone(), obj.get_data(desc).borrow().copy()), Some(desc) => out.add(desc.clone(), obj.get_data(desc).borrow().clone()),
} }
} }
@ -539,7 +528,7 @@ crate fn reject_fields(obj: &Value, fields: &[String]) -> crate::object::Diction
for desc in descs { for desc in descs {
match desc { match desc {
x if fields.iter().any(|field| *field == x) => continue, x if fields.iter().any(|field| *field == x) => continue,
_ => out.add(desc.clone(), obj.get_data(&desc).borrow().copy()), _ => out.add(desc.clone(), obj.get_data(&desc).borrow().clone()),
} }
} }
@ -552,7 +541,7 @@ crate fn find(obj: &Value, field: &str, op: &Operator, rhs: &Value) -> bool {
match descs.iter().find(|d| *d == field) { match descs.iter().find(|d| *d == field) {
None => false, None => false,
Some(desc) => { Some(desc) => {
let v = obj.get_data(desc).borrow().copy(); let v = obj.get_data(desc).borrow().clone();
match v { match v {
Value::Primitive(Primitive::Boolean(b)) => match (op, rhs) { Value::Primitive(Primitive::Boolean(b)) => match (op, rhs) {

View File

@ -16,24 +16,31 @@ const APP_INFO: AppInfo = AppInfo {
#[derive(Deserialize, Serialize)] #[derive(Deserialize, Serialize)]
struct Config { struct Config {
#[serde(flatten)] #[serde(flatten)]
extra: IndexMap<String, Value>, extra: IndexMap<String, Spanned<Value>>,
} }
crate fn write_config(map: &IndexMap<String, Value>) -> Result<(), ShellError> { crate fn write_config(config: &IndexMap<String, Spanned<Value>>) -> Result<(), ShellError> {
let location = app_root(AppDataType::UserConfig, &APP_INFO) let location = app_root(AppDataType::UserConfig, &APP_INFO)
.map_err(|err| ShellError::string(&format!("Couldn't open config file:\n{}", err)))?; .map_err(|err| ShellError::string(&format!("Couldn't open config file:\n{}", err)))?;
let filename = location.join("config.toml"); let filename = location.join("config.toml");
touch(&filename)?; touch(&filename)?;
let contents = toml::to_string(&Config { extra: map.clone() })?; let contents = toml::to_string(&Config {
extra: config
.iter()
.map(|(k, v)| (k.clone(), v.item.clone()))
.collect(),
})?;
fs::write(&filename, &contents)?; fs::write(&filename, &contents)?;
Ok(()) Ok(())
} }
crate fn config() -> Result<IndexMap<String, Value>, ShellError> { crate fn config(span: impl Into<Span>) -> Result<IndexMap<String, Spanned<Value>>, ShellError> {
let span = span.into();
let location = app_root(AppDataType::UserConfig, &APP_INFO) let location = app_root(AppDataType::UserConfig, &APP_INFO)
.map_err(|err| ShellError::string(&format!("Couldn't open config file:\n{}", err)))?; .map_err(|err| ShellError::string(&format!("Couldn't open config file:\n{}", err)))?;
@ -43,9 +50,11 @@ crate fn config() -> Result<IndexMap<String, Value>, ShellError> {
trace!("config file = {}", filename.display()); trace!("config file = {}", filename.display());
let contents = fs::read_to_string(filename) let contents = fs::read_to_string(filename)
.map(|v| v.spanned(span))
.map_err(|err| ShellError::string(&format!("Couldn't read config file:\n{}", err)))?; .map_err(|err| ShellError::string(&format!("Couldn't read config file:\n{}", err)))?;
let parsed: Config = toml::from_str(&contents) 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)))?; .map_err(|err| ShellError::string(&format!("Couldn't parse config file:\n{}", err)))?;
Ok(parsed.extra) Ok(parsed.extra)

View File

@ -9,7 +9,7 @@ use std::fmt;
#[derive(Debug, Default, Eq, PartialEq, Serialize, Deserialize, Clone, new)] #[derive(Debug, Default, Eq, PartialEq, Serialize, Deserialize, Clone, new)]
pub struct Dictionary { pub struct Dictionary {
pub entries: IndexMap<String, Value>, pub entries: IndexMap<String, Spanned<Value>>,
} }
impl PartialOrd for Dictionary { impl PartialOrd for Dictionary {
@ -28,8 +28,8 @@ impl PartialOrd for Dictionary {
} }
} }
impl From<IndexMap<String, Value>> for Dictionary { impl From<IndexMap<String, Spanned<Value>>> for Dictionary {
fn from(input: IndexMap<String, Value>) -> Dictionary { fn from(input: IndexMap<String, Spanned<Value>>) -> Dictionary {
let mut out = IndexMap::default(); let mut out = IndexMap::default();
for (key, value) in input { for (key, value) in input {
@ -93,7 +93,7 @@ impl Dictionary {
} }
} }
crate fn get_data_by_key(&self, name: &str) -> Option<&Value> { crate fn get_data_by_key(&self, name: &str) -> Option<&Spanned<Value>> {
match self match self
.entries .entries
.iter() .iter()
@ -114,3 +114,41 @@ impl Dictionary {
debug.finish() debug.finish()
} }
} }
#[derive(Debug)]
pub struct SpannedDictBuilder {
span: Span,
dict: IndexMap<DataDescriptor, Spanned<Value>>,
}
impl SpannedDictBuilder {
pub fn new(span: impl Into<Span>) -> SpannedDictBuilder {
SpannedDictBuilder {
span: span.into(),
dict: IndexMap::default(),
}
}
pub fn insert(&mut self, key: impl Into<DataDescriptor>, value: impl Into<Value>) {
self.dict
.insert(key.into(), value.into().spanned(self.span));
}
pub fn insert_spanned(
&mut self,
key: impl Into<DataDescriptor>,
value: impl Into<Spanned<Value>>,
) {
self.dict.insert(key.into(), value.into());
}
pub fn into_spanned_value(self) -> Spanned<Value> {
Value::Object(Dictionary { entries: self.dict }).spanned(self.span)
}
}
impl From<SpannedDictBuilder> for Spanned<Value> {
fn from(input: SpannedDictBuilder) -> Spanned<Value> {
input.into_spanned_value()
}
}

23
src/object/into.rs Normal file
View File

@ -0,0 +1,23 @@
use crate::object::{Primitive, Value};
use crate::prelude::*;
impl From<Primitive> for Value {
fn from(input: Primitive) -> Value {
Value::Primitive(input)
}
}
impl From<String> for Value {
fn from(input: String) -> Value {
Value::Primitive(Primitive::String(input))
}
}
impl<T: Into<Value>> Spanned<T> {
pub fn into_spanned_value(self) -> Spanned<Value> {
let Spanned { item, span } = self;
let value = item.into();
value.spanned(span)
}
}

View File

@ -2,29 +2,44 @@ use crate::object::base as value;
use crate::parser::hir; use crate::parser::hir;
use crate::prelude::*; use crate::prelude::*;
use derive_new::new; use derive_new::new;
use serde_derive::{Deserialize, Serialize}; use serde_derive::Deserialize;
pub trait Type: std::fmt::Debug + Send { pub trait Type: std::fmt::Debug + Send {
type Extractor: ExtractType;
fn name(&self) -> &'static str; fn name(&self) -> &'static str;
fn check(&self, value: Spanned<Value>) -> Result<Spanned<Value>, ShellError>; fn check(&self, value: &'value Spanned<Value>) -> Result<&'value Spanned<Value>, ShellError>;
fn coerce(&self) -> Option<hir::ExpressionKindHint> { fn coerce(&self) -> Option<hir::ExpressionKindHint> {
None None
} }
} }
pub trait ExtractType<T>: Type { pub trait ExtractType: Sized {
fn extract(value: Value) -> T; fn extract(value: &Spanned<Value>) -> Result<Self, ShellError>;
fn check(value: &'value Spanned<Value>) -> Result<&'value Spanned<Value>, ShellError>;
} }
#[derive(Debug, Deserialize, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, new)] #[derive(Debug, Deserialize, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, new)]
pub struct Any; pub struct Any;
impl Type for Any { impl Type for Any {
type Extractor = Spanned<Value>;
fn name(&self) -> &'static str { fn name(&self) -> &'static str {
"Any" "Any"
} }
fn check(&self, value: Spanned<Value>) -> Result<Spanned<Value>, ShellError> { fn check(&self, value: &'value Spanned<Value>) -> Result<&'value Spanned<Value>, ShellError> {
Ok(value)
}
}
impl ExtractType for Spanned<Value> {
fn extract(value: &Spanned<Value>) -> Result<Self, ShellError> {
Ok(value.clone())
}
fn check(&self, value: &'value Spanned<Value>) -> Result<&'value Spanned<Value>, ShellError> {
Ok(value) Ok(value)
} }
} }
@ -33,11 +48,13 @@ impl Type for Any {
pub struct Integer; pub struct Integer;
impl Type for Integer { impl Type for Integer {
type Extractor = i64;
fn name(&self) -> &'static str { fn name(&self) -> &'static str {
"Integer" "Integer"
} }
fn check(&self, value: Spanned<Value>) -> Result<Spanned<Value>, ShellError> { fn check(&self, value: &'value Spanned<Value>) -> Result<&'value Spanned<Value>, ShellError> {
match value { match value {
v @ Spanned { v @ Spanned {
item: Value::Primitive(Primitive::Int(_)), item: Value::Primitive(Primitive::Int(_)),
@ -48,11 +65,67 @@ impl Type for Integer {
} }
} }
impl ExtractType<i64> for Integer { impl ExtractType for i64 {
fn extract(value: Value) -> i64 { fn extract(value: &Spanned<Value>) -> Result<i64, ShellError> {
match value { match value {
Value::Primitive(Primitive::Int(int)) => int, &Spanned {
_ => unreachable!("invariant: must check before extract"), item: Value::Primitive(Primitive::Int(int)),
..
} => Ok(int),
other => Err(ShellError::type_error("Integer", other.spanned_type_name())),
}
}
fn check(&self, value: &'value Spanned<Value>) -> Result<&'value Spanned<Value>, ShellError> {
match value {
v @ Spanned {
item: Value::Primitive(Primitive::Int(_)),
..
} => Ok(v),
other => Err(ShellError::type_error("Integer", other.spanned_type_name())),
}
}
}
#[derive(Debug, Deserialize, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, new)]
pub struct NuString;
impl Type for NuString {
type Extractor = String;
fn name(&self) -> &'static str {
"Integer"
}
fn check(&self, value: &'value Spanned<Value>) -> Result<&'value Spanned<Value>, 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 {
fn extract(value: &Spanned<Value>) -> Result<String, ShellError> {
match value {
Spanned {
item: Value::Primitive(Primitive::String(string)),
..
} => Ok(string.clone()),
other => Err(ShellError::type_error("String", other.spanned_type_name())),
}
}
fn check(&self, value: &'value Spanned<Value>) -> Result<&'value Spanned<Value>, ShellError> {
match value {
v @ Spanned {
item: Value::Primitive(Primitive::Int(_)),
..
} => Ok(v),
other => Err(ShellError::type_error("Integer", other.spanned_type_name())),
} }
} }
} }
@ -61,11 +134,13 @@ impl ExtractType<i64> for Integer {
pub struct Block; pub struct Block;
impl Type for Block { impl Type for Block {
type Extractor = value::Block;
fn name(&self) -> &'static str { fn name(&self) -> &'static str {
"Block" "Block"
} }
fn check(&self, value: Spanned<Value>) -> Result<Spanned<Value>, ShellError> { fn check(&self, value: &'value Spanned<Value>) -> Result<&'value Spanned<Value>, ShellError> {
match value { match value {
v @ Spanned { v @ Spanned {
item: Value::Block(_), item: Value::Block(_),
@ -76,11 +151,24 @@ impl Type for Block {
} }
} }
impl ExtractType<value::Block> for Block { impl ExtractType for value::Block {
fn extract(value: Value) -> value::Block { fn extract(value: &Spanned<Value>) -> Result<value::Block, ShellError> {
match value { match value {
Value::Block(block) => block, Spanned {
_ => unreachable!("invariant: must check before extract"), item: Value::Block(block),
..
} => Ok(block.clone()),
other => Err(ShellError::type_error("Block", other.spanned_type_name())),
}
}
fn check(&self, value: &'value Spanned<Value>) -> Result<&'value Spanned<Value>, ShellError> {
match value {
v @ Spanned {
item: Value::Block(_),
..
} => Ok(v),
other => Err(ShellError::type_error("Block", other.spanned_type_name())),
} }
} }
} }

View File

@ -12,7 +12,7 @@ crate use parse::flag::Flag;
crate use parse::operator::Operator; crate use parse::operator::Operator;
crate use parse::parser::{nom_input, pipeline}; crate use parse::parser::{nom_input, pipeline};
crate use parse::pipeline::{Pipeline, PipelineElement}; crate use parse::pipeline::{Pipeline, PipelineElement};
pub use parse::span::{Span, Spanned}; pub use parse::span::{Span, Spanned, SpannedItem};
crate use parse::text::Text; crate use parse::text::Text;
crate use parse::token_tree::{DelimitedNode, Delimiter, PathNode, TokenNode}; crate use parse::token_tree::{DelimitedNode, Delimiter, PathNode, TokenNode};
crate use parse::tokens::{RawToken, Token}; crate use parse::tokens::{RawToken, Token};

View File

@ -16,6 +16,13 @@ pub trait SpannedItem: Sized {
fn spanned(self, span: impl Into<Span>) -> Spanned<Self> { fn spanned(self, span: impl Into<Span>) -> Spanned<Self> {
Spanned::from_item(self, span.into()) Spanned::from_item(self, span.into())
} }
// For now, this is a temporary facility. In many cases, there are other useful spans that we
// could be using, such as the original source spans of JSON or Toml files, but we don't yet
// have the infrastructure to make that work.
fn spanned_unknown(self) -> Spanned<Self> {
Spanned::from_item(self, (0, 0))
}
} }
impl<T> SpannedItem for T {} impl<T> SpannedItem for T {}
@ -64,6 +71,15 @@ pub struct Span {
// source: &'source str, // source: &'source str,
} }
impl From<Option<Span>> for Span {
fn from(input: Option<Span>) -> Span {
match input {
None => Span { start: 0, end: 0 },
Some(span) => span,
}
}
}
impl<T> From<&Spanned<T>> for Span { impl<T> From<&Spanned<T>> for Span {
fn from(input: &Spanned<T>) -> Span { fn from(input: &Spanned<T>) -> Span {
input.span input.span
@ -113,6 +129,14 @@ impl From<&std::ops::Range<usize>> for Span {
} }
impl Span { impl Span {
pub fn unknown() -> Span {
Span { start: 0, end: 0 }
}
pub fn is_unknown(&self) -> bool {
self.start == 0 && self.end == 0
}
pub fn slice(&self, source: &'a str) -> &'a str { pub fn slice(&self, source: &'a str) -> &'a str {
&source[self.start..self.end] &source[self.start..self.end]
} }

View File

@ -42,7 +42,7 @@ crate use crate::env::{Environment, Host};
crate use crate::errors::ShellError; crate use crate::errors::ShellError;
crate use crate::object::types::{ExtractType, Type}; crate use crate::object::types::{ExtractType, Type};
crate use crate::object::{Primitive, Value}; crate use crate::object::{Primitive, Value};
crate use crate::parser::{Span, Spanned}; crate use crate::parser::{Span, Spanned, SpannedItem};
crate use crate::stream::{InputStream, OutputStream}; crate use crate::stream::{InputStream, OutputStream};
crate use crate::Text; crate use crate::Text;
crate use futures::stream::BoxStream; crate use futures::stream::BoxStream;
@ -58,7 +58,7 @@ pub trait FromInputStream {
impl<T> FromInputStream for T impl<T> FromInputStream for T
where where
T: Stream<Item = Value> + Send + 'static, T: Stream<Item = Spanned<Value>> + Send + 'static,
{ {
fn from_input_stream(self) -> OutputStream { fn from_input_stream(self) -> OutputStream {
OutputStream { OutputStream {

View File

@ -1,15 +1,15 @@
use crate::prelude::*; use crate::prelude::*;
pub struct InputStream { pub struct InputStream {
crate values: BoxStream<'static, Value>, crate values: BoxStream<'static, Spanned<Value>>,
} }
impl InputStream { impl InputStream {
pub fn into_vec(self) -> impl Future<Output = Vec<Value>> { pub fn into_vec(self) -> impl Future<Output = Vec<Spanned<Value>>> {
self.values.collect() self.values.collect()
} }
pub fn from_stream(input: impl Stream<Item = Value> + Send + 'static) -> InputStream { pub fn from_stream(input: impl Stream<Item = Spanned<Value>> + Send + 'static) -> InputStream {
InputStream { InputStream {
values: input.boxed(), values: input.boxed(),
} }
@ -22,8 +22,8 @@ impl From<BoxStream<'static, Value>> for InputStream {
} }
} }
impl From<VecDeque<Value>> for InputStream { impl From<VecDeque<Spanned<Value>>> for InputStream {
fn from(input: VecDeque<Value>) -> InputStream { fn from(input: VecDeque<Spanned<Value>>) -> InputStream {
InputStream { InputStream {
values: input.boxed(), values: input.boxed(),
} }
@ -46,13 +46,7 @@ pub struct OutputStream {
} }
impl OutputStream { impl OutputStream {
pub fn from_stream(input: impl Stream<Item = ReturnValue> + Send + 'static) -> OutputStream { pub fn from_input(input: impl Stream<Item = Spanned<Value>> + Send + 'static) -> OutputStream {
OutputStream {
values: input.boxed(),
}
}
pub fn from_input(input: impl Stream<Item = Value> + Send + 'static) -> OutputStream {
OutputStream { OutputStream {
values: input.map(ReturnSuccess::value).boxed(), values: input.map(ReturnSuccess::value).boxed(),
} }