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) => {
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 JSON string", "Can not convert to JSON string",
"can not convert piped data to JSON string", "can not convert piped data to JSON string",
span, span,
)), )),
}, })
) .to_output_stream())
.boxed())
} }

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.copy()) .map(|v| v.clone())
.unwrap_or_else(|| Value::nothing()), .unwrap_or_else(|| Value::nothing().spanned(span))),
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(),
} }