2019-05-11 22:59:57 +00:00
|
|
|
use crate::errors::ShellError;
|
2019-06-22 03:43:37 +00:00
|
|
|
use crate::evaluate::{evaluate_baseline_expr, Scope};
|
2019-08-01 01:58:42 +00:00
|
|
|
use crate::object::TaggedDictBuilder;
|
|
|
|
use crate::parser::{hir, Operator};
|
2019-05-23 04:30:43 +00:00
|
|
|
use crate::prelude::*;
|
2019-06-22 20:46:16 +00:00
|
|
|
use crate::Text;
|
2019-05-15 22:23:36 +00:00
|
|
|
use ansi_term::Color;
|
2019-05-15 18:14:51 +00:00
|
|
|
use chrono::{DateTime, Utc};
|
|
|
|
use chrono_humanize::Humanize;
|
2019-05-26 06:54:41 +00:00
|
|
|
use derive_new::new;
|
2019-05-17 16:59:25 +00:00
|
|
|
use ordered_float::OrderedFloat;
|
2019-06-29 08:55:42 +00:00
|
|
|
use serde::{ser::SerializeSeq, Deserialize, Deserializer, Serialize, Serializer};
|
2019-06-22 03:43:37 +00:00
|
|
|
use std::fmt;
|
2019-07-15 21:16:27 +00:00
|
|
|
use std::path::PathBuf;
|
2019-05-15 18:14:51 +00:00
|
|
|
use std::time::SystemTime;
|
2019-05-10 16:59:12 +00:00
|
|
|
|
2019-06-30 06:46:49 +00:00
|
|
|
#[derive(Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq, new, Serialize, Deserialize)]
|
2019-06-01 05:50:16 +00:00
|
|
|
pub struct OF64 {
|
|
|
|
crate inner: OrderedFloat<f64>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl OF64 {
|
|
|
|
crate fn into_inner(&self) -> f64 {
|
|
|
|
self.inner.into_inner()
|
|
|
|
}
|
|
|
|
}
|
2019-05-17 16:59:25 +00:00
|
|
|
|
2019-06-01 05:50:16 +00:00
|
|
|
impl From<f64> for OF64 {
|
|
|
|
fn from(float: f64) -> Self {
|
|
|
|
OF64::new(OrderedFloat(float))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-30 06:46:49 +00:00
|
|
|
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Deserialize, Serialize)]
|
2019-05-10 16:59:12 +00:00
|
|
|
pub enum Primitive {
|
|
|
|
Nothing,
|
|
|
|
Int(i64),
|
2019-05-15 22:58:44 +00:00
|
|
|
#[allow(unused)]
|
2019-05-17 16:59:25 +00:00
|
|
|
Float(OF64),
|
2019-06-30 06:46:49 +00:00
|
|
|
Bytes(u64),
|
2019-05-10 16:59:12 +00:00
|
|
|
String(String),
|
|
|
|
Boolean(bool),
|
2019-05-15 18:14:51 +00:00
|
|
|
Date(DateTime<Utc>),
|
2019-07-15 21:16:27 +00:00
|
|
|
Path(PathBuf),
|
2019-06-27 16:47:24 +00:00
|
|
|
|
2019-07-27 07:45:00 +00:00
|
|
|
// Stream markers (used as bookend markers rather than actual values)
|
|
|
|
BeginningOfStream,
|
2019-06-27 16:47:24 +00:00
|
|
|
EndOfStream,
|
2019-05-10 16:59:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Primitive {
|
2019-06-03 05:11:21 +00:00
|
|
|
crate fn type_name(&self) -> String {
|
|
|
|
use Primitive::*;
|
|
|
|
|
|
|
|
match self {
|
|
|
|
Nothing => "nothing",
|
2019-07-27 07:45:00 +00:00
|
|
|
BeginningOfStream => "beginning-of-stream",
|
2019-06-27 16:47:24 +00:00
|
|
|
EndOfStream => "end-of-stream",
|
2019-07-15 21:16:27 +00:00
|
|
|
Path(_) => "path",
|
2019-06-03 05:11:21 +00:00
|
|
|
Int(_) => "int",
|
|
|
|
Float(_) => "float",
|
|
|
|
Bytes(_) => "bytes",
|
|
|
|
String(_) => "string",
|
|
|
|
Boolean(_) => "boolean",
|
|
|
|
Date(_) => "date",
|
|
|
|
}
|
|
|
|
.to_string()
|
|
|
|
}
|
|
|
|
|
2019-06-22 03:43:37 +00:00
|
|
|
crate fn debug(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
use Primitive::*;
|
|
|
|
|
|
|
|
match self {
|
|
|
|
Nothing => write!(f, "Nothing"),
|
2019-07-27 07:45:00 +00:00
|
|
|
BeginningOfStream => write!(f, "BeginningOfStream"),
|
2019-06-27 16:47:24 +00:00
|
|
|
EndOfStream => write!(f, "EndOfStream"),
|
2019-06-22 03:43:37 +00:00
|
|
|
Int(int) => write!(f, "{}", int),
|
2019-07-15 21:16:27 +00:00
|
|
|
Path(path) => write!(f, "{}", path.display()),
|
2019-06-22 03:43:37 +00:00
|
|
|
Float(float) => write!(f, "{:?}", float),
|
|
|
|
Bytes(bytes) => write!(f, "{}", bytes),
|
|
|
|
String(string) => write!(f, "{:?}", string),
|
|
|
|
Boolean(boolean) => write!(f, "{}", boolean),
|
|
|
|
Date(date) => write!(f, "{}", date),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-04 05:11:56 +00:00
|
|
|
pub fn format(&self, field_name: Option<&String>) -> String {
|
2019-05-10 16:59:12 +00:00
|
|
|
match self {
|
2019-05-15 22:23:36 +00:00
|
|
|
Primitive::Nothing => format!("{}", Color::Black.bold().paint("-")),
|
2019-07-27 07:45:00 +00:00
|
|
|
Primitive::BeginningOfStream => format!("{}", Color::Black.bold().paint("-")),
|
2019-06-27 16:47:24 +00:00
|
|
|
Primitive::EndOfStream => format!("{}", Color::Black.bold().paint("-")),
|
2019-07-15 21:16:27 +00:00
|
|
|
Primitive::Path(p) => format!("{}", p.display()),
|
2019-05-15 18:14:51 +00:00
|
|
|
Primitive::Bytes(b) => {
|
2019-06-30 06:46:49 +00:00
|
|
|
let byte = byte_unit::Byte::from_bytes(*b as u128);
|
2019-05-15 22:23:36 +00:00
|
|
|
|
|
|
|
if byte.get_bytes() == 0u128 {
|
|
|
|
return Color::Black.bold().paint("Empty".to_string()).to_string();
|
|
|
|
}
|
|
|
|
|
2019-05-28 05:05:14 +00:00
|
|
|
let byte = byte.get_appropriate_unit(false);
|
2019-05-15 18:14:51 +00:00
|
|
|
|
|
|
|
match byte.get_unit() {
|
|
|
|
byte_unit::ByteUnit::B => format!("{}", byte.format(0)),
|
|
|
|
_ => format!("{}", byte.format(1)),
|
|
|
|
}
|
|
|
|
}
|
2019-05-10 16:59:12 +00:00
|
|
|
Primitive::Int(i) => format!("{}", i),
|
2019-06-01 05:50:16 +00:00
|
|
|
Primitive::Float(OF64 { inner: f }) => format!("{:.*}", 2, f.into_inner()),
|
2019-05-15 18:14:51 +00:00
|
|
|
Primitive::String(s) => format!("{}", s),
|
|
|
|
Primitive::Boolean(b) => match (b, field_name) {
|
|
|
|
(true, None) => format!("Yes"),
|
|
|
|
(false, None) => format!("No"),
|
2019-07-03 17:37:09 +00:00
|
|
|
(true, Some(s)) if !s.is_empty() => format!("{}", s),
|
|
|
|
(false, Some(s)) if !s.is_empty() => format!(""),
|
2019-06-04 21:42:31 +00:00
|
|
|
(true, Some(_)) => format!("Yes"),
|
|
|
|
(false, Some(_)) => format!("No"),
|
2019-05-15 18:14:51 +00:00
|
|
|
},
|
2019-05-15 22:23:36 +00:00
|
|
|
Primitive::Date(d) => format!("{}", d.humanize()),
|
2019-05-10 16:59:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-28 02:01:37 +00:00
|
|
|
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Clone, new, Serialize)]
|
2019-05-26 06:54:41 +00:00
|
|
|
pub struct Operation {
|
|
|
|
crate left: Value,
|
|
|
|
crate operator: Operator,
|
|
|
|
crate right: Value,
|
|
|
|
}
|
|
|
|
|
2019-05-28 06:45:18 +00:00
|
|
|
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Clone, new)]
|
|
|
|
pub struct Block {
|
2019-06-29 08:55:42 +00:00
|
|
|
crate expressions: Vec<hir::Expression>,
|
2019-06-22 03:43:37 +00:00
|
|
|
crate source: Text,
|
2019-06-29 08:55:42 +00:00
|
|
|
crate span: Span,
|
2019-05-28 06:45:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Serialize for Block {
|
|
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
|
|
where
|
|
|
|
S: Serializer,
|
|
|
|
{
|
2019-06-29 08:55:42 +00:00
|
|
|
let mut seq = serializer.serialize_seq(None)?;
|
|
|
|
|
|
|
|
let list = self
|
|
|
|
.expressions
|
|
|
|
.iter()
|
|
|
|
.map(|e| e.source(&self.source.clone()));
|
|
|
|
|
|
|
|
for item in list {
|
|
|
|
seq.serialize_element(item.as_ref())?;
|
|
|
|
}
|
|
|
|
|
|
|
|
seq.end()
|
2019-05-28 06:45:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-01 05:50:16 +00:00
|
|
|
impl Deserialize<'de> for Block {
|
|
|
|
fn deserialize<D>(_deserializer: D) -> Result<Self, D::Error>
|
|
|
|
where
|
|
|
|
D: Deserializer<'de>,
|
|
|
|
{
|
2019-06-22 03:43:37 +00:00
|
|
|
unimplemented!("deserialize block")
|
2019-06-01 05:50:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-28 06:45:18 +00:00
|
|
|
impl Block {
|
2019-08-01 01:58:42 +00:00
|
|
|
pub fn invoke(&self, value: &Tagged<Value>) -> Result<Tagged<Value>, ShellError> {
|
2019-07-08 16:44:53 +00:00
|
|
|
let scope = Scope::new(value.clone());
|
2019-06-29 08:55:42 +00:00
|
|
|
|
|
|
|
if self.expressions.len() == 0 {
|
2019-08-01 01:58:42 +00:00
|
|
|
return Ok(Tagged::from_item(Value::nothing(), self.span));
|
2019-06-29 08:55:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let mut last = None;
|
|
|
|
|
|
|
|
for expr in self.expressions.iter() {
|
|
|
|
last = Some(evaluate_baseline_expr(&expr, &(), &scope, &self.source)?)
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(last.unwrap())
|
2019-05-28 06:45:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-30 06:46:49 +00:00
|
|
|
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Serialize, Deserialize)]
|
2019-05-10 16:59:12 +00:00
|
|
|
pub enum Value {
|
|
|
|
Primitive(Primitive),
|
2019-05-15 21:44:06 +00:00
|
|
|
Object(crate::object::Dictionary),
|
2019-07-15 18:34:44 +00:00
|
|
|
#[serde(with = "serde_bytes")]
|
2019-07-04 05:11:56 +00:00
|
|
|
Binary(Vec<u8>),
|
2019-08-01 01:58:42 +00:00
|
|
|
List(Vec<Tagged<Value>>),
|
2019-06-22 03:43:37 +00:00
|
|
|
#[allow(unused)]
|
2019-05-28 06:45:18 +00:00
|
|
|
Block(Block),
|
2019-05-10 16:59:12 +00:00
|
|
|
}
|
|
|
|
|
2019-08-01 01:58:42 +00:00
|
|
|
pub fn debug_list(values: &'a Vec<Tagged<Value>>) -> ValuesDebug<'a> {
|
2019-06-22 03:43:37 +00:00
|
|
|
ValuesDebug { values }
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct ValuesDebug<'a> {
|
2019-08-01 01:58:42 +00:00
|
|
|
values: &'a Vec<Tagged<Value>>,
|
2019-06-22 03:43:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Debug for ValuesDebug<'a> {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
f.debug_list()
|
|
|
|
.entries(self.values.iter().map(|i| i.debug()))
|
|
|
|
.finish()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct ValueDebug<'a> {
|
2019-08-01 01:58:42 +00:00
|
|
|
value: &'a Tagged<Value>,
|
2019-06-22 03:43:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Debug for ValueDebug<'a> {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
2019-07-08 16:44:53 +00:00
|
|
|
match self.value.item() {
|
2019-06-22 03:43:37 +00:00
|
|
|
Value::Primitive(p) => p.debug(f),
|
|
|
|
Value::Object(o) => o.debug(f),
|
|
|
|
Value::List(l) => debug_list(l).fmt(f),
|
|
|
|
Value::Block(_) => write!(f, "[[block]]"),
|
2019-07-04 05:11:56 +00:00
|
|
|
Value::Binary(_) => write!(f, "[[binary]]"),
|
2019-06-22 03:43:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-01 01:58:42 +00:00
|
|
|
impl Tagged<Value> {
|
|
|
|
crate fn tagged_type_name(&self) -> Tagged<String> {
|
2019-06-24 00:55:31 +00:00
|
|
|
let name = self.type_name();
|
2019-08-01 01:58:42 +00:00
|
|
|
Tagged::from_item(name, self.span())
|
2019-06-24 00:55:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-01 01:58:42 +00:00
|
|
|
impl std::convert::TryFrom<&'a Tagged<Value>> for Block {
|
2019-07-03 20:31:15 +00:00
|
|
|
type Error = ShellError;
|
|
|
|
|
2019-08-01 01:58:42 +00:00
|
|
|
fn try_from(value: &'a Tagged<Value>) -> Result<Block, ShellError> {
|
2019-07-03 20:31:15 +00:00
|
|
|
match value.item() {
|
|
|
|
Value::Block(block) => Ok(block.clone()),
|
|
|
|
v => Err(ShellError::type_error(
|
|
|
|
"Block",
|
|
|
|
value.copy_span(v.type_name()),
|
|
|
|
)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-01 01:58:42 +00:00
|
|
|
impl std::convert::TryFrom<&'a Tagged<Value>> for i64 {
|
2019-07-03 20:31:15 +00:00
|
|
|
type Error = ShellError;
|
|
|
|
|
2019-08-01 01:58:42 +00:00
|
|
|
fn try_from(value: &'a Tagged<Value>) -> Result<i64, ShellError> {
|
2019-07-03 20:31:15 +00:00
|
|
|
match value.item() {
|
|
|
|
Value::Primitive(Primitive::Int(int)) => Ok(*int),
|
|
|
|
v => Err(ShellError::type_error(
|
|
|
|
"Integer",
|
|
|
|
value.copy_span(v.type_name()),
|
|
|
|
)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub enum Switch {
|
|
|
|
Present,
|
|
|
|
Absent,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Switch {
|
|
|
|
pub fn is_present(&self) -> bool {
|
|
|
|
match self {
|
|
|
|
Switch::Present => true,
|
|
|
|
Switch::Absent => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-01 01:58:42 +00:00
|
|
|
impl std::convert::TryFrom<Option<&'a Tagged<Value>>> for Switch {
|
2019-07-03 20:31:15 +00:00
|
|
|
type Error = ShellError;
|
|
|
|
|
2019-08-01 01:58:42 +00:00
|
|
|
fn try_from(value: Option<&'a Tagged<Value>>) -> Result<Switch, ShellError> {
|
2019-07-03 20:31:15 +00:00
|
|
|
match value {
|
|
|
|
None => Ok(Switch::Absent),
|
|
|
|
Some(value) => match value.item() {
|
|
|
|
Value::Primitive(Primitive::Boolean(true)) => Ok(Switch::Present),
|
|
|
|
v => Err(ShellError::type_error(
|
|
|
|
"Boolean",
|
|
|
|
value.copy_span(v.type_name()),
|
|
|
|
)),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-01 01:58:42 +00:00
|
|
|
impl Tagged<Value> {
|
2019-07-08 16:44:53 +00:00
|
|
|
crate fn debug(&'a self) -> ValueDebug<'a> {
|
|
|
|
ValueDebug { value: self }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-15 22:23:36 +00:00
|
|
|
impl Value {
|
2019-06-03 05:11:21 +00:00
|
|
|
crate fn type_name(&self) -> String {
|
|
|
|
match self {
|
|
|
|
Value::Primitive(p) => p.type_name(),
|
|
|
|
Value::Object(_) => format!("object"),
|
|
|
|
Value::List(_) => format!("list"),
|
|
|
|
Value::Block(_) => format!("block"),
|
2019-07-04 05:11:56 +00:00
|
|
|
Value::Binary(_) => format!("binary"),
|
2019-06-03 05:11:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-04 05:11:56 +00:00
|
|
|
pub fn data_descriptors(&self) -> Vec<String> {
|
2019-05-10 16:59:12 +00:00
|
|
|
match self {
|
2019-07-03 17:37:09 +00:00
|
|
|
Value::Primitive(_) => vec![],
|
|
|
|
Value::Object(o) => o
|
|
|
|
.entries
|
|
|
|
.keys()
|
|
|
|
.into_iter()
|
|
|
|
.map(|x| x.to_string())
|
|
|
|
.collect(),
|
|
|
|
Value::Block(_) => vec![],
|
2019-05-15 22:58:44 +00:00
|
|
|
Value::List(_) => vec![],
|
2019-07-04 05:11:56 +00:00
|
|
|
Value::Binary(_) => vec![],
|
2019-05-10 16:59:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-01 01:58:42 +00:00
|
|
|
crate fn get_data_by_key(&'a self, name: &str) -> Option<&Tagged<Value>> {
|
2019-05-17 15:55:50 +00:00
|
|
|
match self {
|
|
|
|
Value::Object(o) => o.get_data_by_key(name),
|
2019-06-11 06:26:03 +00:00
|
|
|
Value::List(l) => {
|
|
|
|
for item in l {
|
|
|
|
match item {
|
2019-08-01 01:58:42 +00:00
|
|
|
Tagged {
|
2019-07-08 16:44:53 +00:00
|
|
|
item: Value::Object(o),
|
|
|
|
..
|
|
|
|
} => match o.get_data_by_key(name) {
|
2019-06-11 06:26:03 +00:00
|
|
|
Some(v) => return Some(v),
|
|
|
|
None => {}
|
2019-06-13 21:47:25 +00:00
|
|
|
},
|
2019-06-11 06:26:03 +00:00
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None
|
|
|
|
}
|
2019-05-28 06:45:18 +00:00
|
|
|
_ => None,
|
2019-05-17 15:55:50 +00:00
|
|
|
}
|
2019-06-14 01:59:13 +00:00
|
|
|
}
|
|
|
|
|
2019-07-16 19:10:25 +00:00
|
|
|
#[allow(unused)]
|
2019-08-01 01:58:42 +00:00
|
|
|
crate fn get_data_by_index(&'a self, idx: usize) -> Option<&Tagged<Value>> {
|
2019-06-14 01:59:13 +00:00
|
|
|
match self {
|
|
|
|
Value::List(l) => l.iter().nth(idx),
|
|
|
|
_ => None,
|
|
|
|
}
|
2019-05-17 15:55:50 +00:00
|
|
|
}
|
|
|
|
|
2019-08-01 01:58:42 +00:00
|
|
|
pub fn get_data_by_path(&'a self, span: Span, path: &str) -> Option<Tagged<&Value>> {
|
2019-07-18 01:32:19 +00:00
|
|
|
let mut current = self;
|
|
|
|
for p in path.split(".") {
|
|
|
|
match current.get_data_by_key(p) {
|
|
|
|
Some(v) => current = v,
|
|
|
|
None => return None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-01 01:58:42 +00:00
|
|
|
Some(Tagged::from_item(current, span))
|
2019-07-18 01:32:19 +00:00
|
|
|
}
|
|
|
|
|
2019-07-22 03:52:57 +00:00
|
|
|
pub fn insert_data_at_path(
|
|
|
|
&'a self,
|
|
|
|
span: Span,
|
|
|
|
path: &str,
|
|
|
|
new_value: Value,
|
2019-08-01 01:58:42 +00:00
|
|
|
) -> Option<Tagged<Value>> {
|
2019-07-22 03:52:57 +00:00
|
|
|
let mut new_obj = self.clone();
|
|
|
|
|
|
|
|
let split_path: Vec<_> = path.split(".").collect();
|
|
|
|
|
|
|
|
if let Value::Object(ref mut o) = new_obj {
|
|
|
|
let mut current = o;
|
|
|
|
for idx in 0..split_path.len() - 1 {
|
|
|
|
match current.entries.get_mut(split_path[idx]) {
|
|
|
|
Some(next) => {
|
|
|
|
if idx == (split_path.len() - 2) {
|
|
|
|
match &mut next.item {
|
|
|
|
Value::Object(o) => {
|
|
|
|
o.entries.insert(
|
|
|
|
split_path[idx + 1].to_string(),
|
2019-08-01 01:58:42 +00:00
|
|
|
Tagged::from_item(new_value, span),
|
2019-07-22 03:52:57 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
|
2019-08-01 01:58:42 +00:00
|
|
|
return Some(Tagged::from_item(new_obj, span));
|
2019-07-22 03:52:57 +00:00
|
|
|
} else {
|
|
|
|
match next.item {
|
|
|
|
Value::Object(ref mut o) => {
|
|
|
|
current = o;
|
|
|
|
}
|
|
|
|
_ => return None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => return None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
None
|
|
|
|
}
|
|
|
|
|
2019-07-18 01:32:19 +00:00
|
|
|
pub fn replace_data_at_path(
|
|
|
|
&'a self,
|
|
|
|
span: Span,
|
|
|
|
path: &str,
|
|
|
|
replaced_value: Value,
|
2019-08-01 01:58:42 +00:00
|
|
|
) -> Option<Tagged<Value>> {
|
2019-07-18 01:32:19 +00:00
|
|
|
let mut new_obj = self.clone();
|
|
|
|
|
|
|
|
let split_path: Vec<_> = path.split(".").collect();
|
|
|
|
|
|
|
|
if let Value::Object(ref mut o) = new_obj {
|
|
|
|
let mut current = o;
|
|
|
|
for idx in 0..split_path.len() {
|
|
|
|
match current.entries.get_mut(split_path[idx]) {
|
|
|
|
Some(next) => {
|
|
|
|
if idx == (split_path.len() - 1) {
|
2019-08-01 01:58:42 +00:00
|
|
|
*next = Tagged::from_item(replaced_value, span);
|
|
|
|
return Some(Tagged::from_item(new_obj, span));
|
2019-07-18 01:32:19 +00:00
|
|
|
} else {
|
|
|
|
match next.item {
|
|
|
|
Value::Object(ref mut o) => {
|
|
|
|
current = o;
|
|
|
|
}
|
|
|
|
_ => return None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => return None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
None
|
|
|
|
}
|
|
|
|
|
2019-07-04 05:11:56 +00:00
|
|
|
pub fn get_data(&'a self, desc: &String) -> MaybeOwned<'a, Value> {
|
2019-05-10 16:59:12 +00:00
|
|
|
match self {
|
2019-05-24 18:48:33 +00:00
|
|
|
p @ Value::Primitive(_) => MaybeOwned::Borrowed(p),
|
2019-05-10 16:59:12 +00:00
|
|
|
Value::Object(o) => o.get_data(desc),
|
2019-05-28 06:45:18 +00:00
|
|
|
Value::Block(_) => MaybeOwned::Owned(Value::nothing()),
|
2019-05-23 04:30:43 +00:00
|
|
|
Value::List(_) => MaybeOwned::Owned(Value::nothing()),
|
2019-07-04 05:11:56 +00:00
|
|
|
Value::Binary(_) => MaybeOwned::Owned(Value::nothing()),
|
2019-05-15 18:14:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-03 17:37:09 +00:00
|
|
|
crate fn format_leaf(&self, desc: Option<&String>) -> String {
|
2019-05-10 16:59:12 +00:00
|
|
|
match self {
|
2019-06-04 21:42:31 +00:00
|
|
|
Value::Primitive(p) => p.format(desc),
|
2019-06-29 08:55:42 +00:00
|
|
|
Value::Block(b) => itertools::join(
|
|
|
|
b.expressions
|
|
|
|
.iter()
|
|
|
|
.map(|e| e.source(&b.source).to_string()),
|
|
|
|
"; ",
|
|
|
|
),
|
2019-07-30 01:54:33 +00:00
|
|
|
Value::Object(_) => format!("[{}]", self.type_name()),
|
|
|
|
Value::List(l) => format!(
|
|
|
|
"[{} {}]",
|
|
|
|
l.len(),
|
|
|
|
if l.len() == 1 { "item" } else { "items" }
|
|
|
|
),
|
2019-07-04 05:11:56 +00:00
|
|
|
Value::Binary(_) => format!("<binary>"),
|
2019-05-10 16:59:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-22 03:43:37 +00:00
|
|
|
#[allow(unused)]
|
2019-06-24 00:55:31 +00:00
|
|
|
crate fn compare(&self, operator: &Operator, other: &Value) -> Result<bool, (String, String)> {
|
2019-05-28 06:45:18 +00:00
|
|
|
match operator {
|
|
|
|
_ => {
|
|
|
|
let coerced = coerce_compare(self, other)?;
|
|
|
|
let ordering = coerced.compare();
|
|
|
|
|
|
|
|
use std::cmp::Ordering;
|
|
|
|
|
|
|
|
let result = match (operator, ordering) {
|
|
|
|
(Operator::Equal, Ordering::Equal) => true,
|
2019-05-30 04:19:46 +00:00
|
|
|
(Operator::NotEqual, Ordering::Less)
|
|
|
|
| (Operator::NotEqual, Ordering::Greater) => true,
|
2019-05-28 06:45:18 +00:00
|
|
|
(Operator::LessThan, Ordering::Less) => true,
|
|
|
|
(Operator::GreaterThan, Ordering::Greater) => true,
|
|
|
|
(Operator::GreaterThanOrEqual, Ordering::Greater)
|
|
|
|
| (Operator::GreaterThanOrEqual, Ordering::Equal) => true,
|
|
|
|
(Operator::LessThanOrEqual, Ordering::Less)
|
|
|
|
| (Operator::LessThanOrEqual, Ordering::Equal) => true,
|
|
|
|
_ => false,
|
|
|
|
};
|
|
|
|
|
2019-06-24 00:55:31 +00:00
|
|
|
Ok(result)
|
2019-05-28 06:45:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-01 05:50:16 +00:00
|
|
|
#[allow(unused)]
|
|
|
|
crate fn is_string(&self, expected: &str) -> bool {
|
|
|
|
match self {
|
|
|
|
Value::Primitive(Primitive::String(s)) if s == expected => true,
|
|
|
|
other => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-01 01:58:42 +00:00
|
|
|
crate fn as_pair(&self) -> Result<(Tagged<Value>, Tagged<Value>), ShellError> {
|
2019-06-01 05:50:16 +00:00
|
|
|
match self {
|
|
|
|
Value::List(list) if list.len() == 2 => Ok((list[0].clone(), list[1].clone())),
|
|
|
|
other => Err(ShellError::string(format!(
|
|
|
|
"Expected pair, got {:?}",
|
|
|
|
other
|
|
|
|
))),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-11 22:59:57 +00:00
|
|
|
crate fn as_string(&self) -> Result<String, ShellError> {
|
|
|
|
match self {
|
2019-06-22 22:20:13 +00:00
|
|
|
Value::Primitive(Primitive::String(s)) => Ok(s.clone()),
|
2019-06-19 05:51:24 +00:00
|
|
|
Value::Primitive(Primitive::Boolean(x)) => Ok(format!("{}", x)),
|
|
|
|
Value::Primitive(Primitive::Float(x)) => Ok(format!("{}", x.into_inner())),
|
|
|
|
Value::Primitive(Primitive::Int(x)) => Ok(format!("{}", x)),
|
|
|
|
Value::Primitive(Primitive::Bytes(x)) => Ok(format!("{}", x)),
|
2019-05-11 22:59:57 +00:00
|
|
|
// TODO: this should definitely be more general with better errors
|
2019-05-13 17:30:51 +00:00
|
|
|
other => Err(ShellError::string(format!(
|
|
|
|
"Expected string, got {:?}",
|
|
|
|
other
|
|
|
|
))),
|
2019-05-11 22:59:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-28 06:45:18 +00:00
|
|
|
crate fn as_i64(&self) -> Result<i64, ShellError> {
|
2019-05-26 06:54:41 +00:00
|
|
|
match self {
|
2019-05-28 06:45:18 +00:00
|
|
|
Value::Primitive(Primitive::Int(i)) => Ok(*i),
|
2019-06-30 06:46:49 +00:00
|
|
|
Value::Primitive(Primitive::Bytes(b)) => Ok(*b as i64),
|
2019-05-26 06:54:41 +00:00
|
|
|
// TODO: this should definitely be more general with better errors
|
|
|
|
other => Err(ShellError::string(format!(
|
2019-05-28 06:45:18 +00:00
|
|
|
"Expected integer, got {:?}",
|
2019-05-26 06:54:41 +00:00
|
|
|
other
|
|
|
|
))),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-28 06:45:18 +00:00
|
|
|
crate fn as_block(&self) -> Result<Block, ShellError> {
|
2019-05-15 16:12:38 +00:00
|
|
|
match self {
|
2019-05-28 06:45:18 +00:00
|
|
|
Value::Block(block) => Ok(block.clone()),
|
2019-05-15 16:12:38 +00:00
|
|
|
// TODO: this should definitely be more general with better errors
|
|
|
|
other => Err(ShellError::string(format!(
|
2019-05-28 06:45:18 +00:00
|
|
|
"Expected block, got {:?}",
|
2019-05-15 16:12:38 +00:00
|
|
|
other
|
|
|
|
))),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-28 06:45:18 +00:00
|
|
|
crate fn is_true(&self) -> bool {
|
|
|
|
match self {
|
|
|
|
Value::Primitive(Primitive::Boolean(true)) => true,
|
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-27 04:56:48 +00:00
|
|
|
pub fn string(s: impl Into<String>) -> Value {
|
2019-05-10 16:59:12 +00:00
|
|
|
Value::Primitive(Primitive::String(s.into()))
|
|
|
|
}
|
|
|
|
|
2019-06-30 06:46:49 +00:00
|
|
|
pub fn bytes(s: impl Into<u64>) -> Value {
|
2019-05-15 18:14:51 +00:00
|
|
|
Value::Primitive(Primitive::Bytes(s.into()))
|
|
|
|
}
|
|
|
|
|
2019-06-27 04:56:48 +00:00
|
|
|
pub fn int(s: impl Into<i64>) -> Value {
|
2019-05-10 16:59:12 +00:00
|
|
|
Value::Primitive(Primitive::Int(s.into()))
|
|
|
|
}
|
|
|
|
|
2019-06-27 04:56:48 +00:00
|
|
|
pub fn float(s: impl Into<OF64>) -> Value {
|
2019-05-17 16:59:25 +00:00
|
|
|
Value::Primitive(Primitive::Float(s.into()))
|
|
|
|
}
|
|
|
|
|
2019-06-27 04:56:48 +00:00
|
|
|
pub fn boolean(s: impl Into<bool>) -> Value {
|
2019-05-16 02:42:44 +00:00
|
|
|
Value::Primitive(Primitive::Boolean(s.into()))
|
|
|
|
}
|
|
|
|
|
2019-06-27 04:56:48 +00:00
|
|
|
pub fn system_date(s: SystemTime) -> Value {
|
2019-05-15 18:14:51 +00:00
|
|
|
Value::Primitive(Primitive::Date(s.into()))
|
|
|
|
}
|
|
|
|
|
2019-06-01 05:50:16 +00:00
|
|
|
#[allow(unused)]
|
2019-06-27 04:56:48 +00:00
|
|
|
pub fn date_from_str(s: &str) -> Result<Value, ShellError> {
|
2019-06-01 05:50:16 +00:00
|
|
|
let date = DateTime::parse_from_rfc3339(s)
|
|
|
|
.map_err(|err| ShellError::string(&format!("Date parse error: {}", err)))?;
|
|
|
|
|
|
|
|
let date = date.with_timezone(&chrono::offset::Utc);
|
|
|
|
|
|
|
|
Ok(Value::Primitive(Primitive::Date(date)))
|
|
|
|
}
|
|
|
|
|
2019-06-27 04:56:48 +00:00
|
|
|
pub fn nothing() -> Value {
|
2019-05-10 16:59:12 +00:00
|
|
|
Value::Primitive(Primitive::Nothing)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-01 01:58:42 +00:00
|
|
|
crate fn select_fields(obj: &Value, fields: &[String], span: impl Into<Span>) -> Tagged<Value> {
|
|
|
|
let mut out = TaggedDictBuilder::new(span);
|
2019-05-15 18:14:51 +00:00
|
|
|
|
|
|
|
let descs = obj.data_descriptors();
|
|
|
|
|
|
|
|
for field in fields {
|
2019-07-13 02:07:06 +00:00
|
|
|
match descs.iter().find(|d| *d == field) {
|
2019-07-09 04:31:26 +00:00
|
|
|
None => out.insert(field, Value::nothing()),
|
|
|
|
Some(desc) => out.insert(desc.clone(), obj.get_data(desc).borrow().clone()),
|
2019-05-15 18:14:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-01 01:58:42 +00:00
|
|
|
out.into_tagged_value()
|
2019-05-10 16:59:12 +00:00
|
|
|
}
|
|
|
|
|
2019-08-01 01:58:42 +00:00
|
|
|
crate fn reject_fields(obj: &Value, fields: &[String], span: impl Into<Span>) -> Tagged<Value> {
|
|
|
|
let mut out = TaggedDictBuilder::new(span);
|
2019-05-15 21:44:06 +00:00
|
|
|
|
|
|
|
let descs = obj.data_descriptors();
|
|
|
|
|
|
|
|
for desc in descs {
|
2019-07-03 17:37:09 +00:00
|
|
|
match desc {
|
|
|
|
x if fields.iter().any(|field| *field == x) => continue,
|
2019-07-09 04:31:26 +00:00
|
|
|
_ => out.insert(desc.clone(), obj.get_data(&desc).borrow().clone()),
|
2019-05-15 21:44:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-01 01:58:42 +00:00
|
|
|
out.into_tagged_value()
|
2019-05-15 21:44:06 +00:00
|
|
|
}
|
2019-05-16 02:42:44 +00:00
|
|
|
|
2019-05-28 06:45:18 +00:00
|
|
|
#[allow(unused)]
|
2019-05-18 01:27:31 +00:00
|
|
|
crate fn find(obj: &Value, field: &str, op: &Operator, rhs: &Value) -> bool {
|
2019-05-16 02:42:44 +00:00
|
|
|
let descs = obj.data_descriptors();
|
2019-07-03 17:37:09 +00:00
|
|
|
match descs.iter().find(|d| *d == field) {
|
2019-05-16 02:42:44 +00:00
|
|
|
None => false,
|
|
|
|
Some(desc) => {
|
2019-07-08 16:44:53 +00:00
|
|
|
let v = obj.get_data(desc).borrow().clone();
|
2019-05-16 02:42:44 +00:00
|
|
|
|
|
|
|
match v {
|
2019-05-16 21:43:36 +00:00
|
|
|
Value::Primitive(Primitive::Boolean(b)) => match (op, rhs) {
|
2019-05-18 01:27:31 +00:00
|
|
|
(Operator::Equal, Value::Primitive(Primitive::Boolean(b2))) => b == *b2,
|
|
|
|
(Operator::NotEqual, Value::Primitive(Primitive::Boolean(b2))) => b != *b2,
|
2019-05-16 21:43:36 +00:00
|
|
|
_ => false,
|
|
|
|
},
|
|
|
|
Value::Primitive(Primitive::Bytes(i)) => match (op, rhs) {
|
2019-06-30 06:46:49 +00:00
|
|
|
(Operator::LessThan, Value::Primitive(Primitive::Int(i2))) => i < (*i2 as u64),
|
2019-05-22 07:12:03 +00:00
|
|
|
(Operator::GreaterThan, Value::Primitive(Primitive::Int(i2))) => {
|
2019-06-30 06:46:49 +00:00
|
|
|
i > (*i2 as u64)
|
2019-05-22 07:12:03 +00:00
|
|
|
}
|
|
|
|
(Operator::LessThanOrEqual, Value::Primitive(Primitive::Int(i2))) => {
|
2019-06-30 06:46:49 +00:00
|
|
|
i <= (*i2 as u64)
|
2019-05-22 07:12:03 +00:00
|
|
|
}
|
|
|
|
(Operator::GreaterThanOrEqual, Value::Primitive(Primitive::Int(i2))) => {
|
2019-06-30 06:46:49 +00:00
|
|
|
i >= (*i2 as u64)
|
2019-05-22 07:12:03 +00:00
|
|
|
}
|
2019-06-30 06:46:49 +00:00
|
|
|
(Operator::Equal, Value::Primitive(Primitive::Int(i2))) => i == (*i2 as u64),
|
|
|
|
(Operator::NotEqual, Value::Primitive(Primitive::Int(i2))) => i != (*i2 as u64),
|
2019-05-16 21:43:36 +00:00
|
|
|
_ => false,
|
|
|
|
},
|
|
|
|
Value::Primitive(Primitive::Int(i)) => match (op, rhs) {
|
2019-05-18 01:27:31 +00:00
|
|
|
(Operator::LessThan, Value::Primitive(Primitive::Int(i2))) => i < *i2,
|
|
|
|
(Operator::GreaterThan, Value::Primitive(Primitive::Int(i2))) => i > *i2,
|
|
|
|
(Operator::LessThanOrEqual, Value::Primitive(Primitive::Int(i2))) => i <= *i2,
|
2019-05-22 07:12:03 +00:00
|
|
|
(Operator::GreaterThanOrEqual, Value::Primitive(Primitive::Int(i2))) => {
|
|
|
|
i >= *i2
|
|
|
|
}
|
2019-05-18 01:27:31 +00:00
|
|
|
(Operator::Equal, Value::Primitive(Primitive::Int(i2))) => i == *i2,
|
|
|
|
(Operator::NotEqual, Value::Primitive(Primitive::Int(i2))) => i != *i2,
|
2019-05-16 21:43:36 +00:00
|
|
|
_ => false,
|
|
|
|
},
|
2019-05-17 16:59:25 +00:00
|
|
|
Value::Primitive(Primitive::Float(i)) => match (op, rhs) {
|
2019-05-18 01:27:31 +00:00
|
|
|
(Operator::LessThan, Value::Primitive(Primitive::Float(i2))) => i < *i2,
|
|
|
|
(Operator::GreaterThan, Value::Primitive(Primitive::Float(i2))) => i > *i2,
|
|
|
|
(Operator::LessThanOrEqual, Value::Primitive(Primitive::Float(i2))) => i <= *i2,
|
2019-05-22 07:12:03 +00:00
|
|
|
(Operator::GreaterThanOrEqual, Value::Primitive(Primitive::Float(i2))) => {
|
|
|
|
i >= *i2
|
|
|
|
}
|
2019-05-18 01:27:31 +00:00
|
|
|
(Operator::Equal, Value::Primitive(Primitive::Float(i2))) => i == *i2,
|
|
|
|
(Operator::NotEqual, Value::Primitive(Primitive::Float(i2))) => i != *i2,
|
2019-05-22 07:12:03 +00:00
|
|
|
(Operator::LessThan, Value::Primitive(Primitive::Int(i2))) => {
|
|
|
|
(i.into_inner()) < *i2 as f64
|
|
|
|
}
|
|
|
|
(Operator::GreaterThan, Value::Primitive(Primitive::Int(i2))) => {
|
|
|
|
i.into_inner() > *i2 as f64
|
|
|
|
}
|
|
|
|
(Operator::LessThanOrEqual, Value::Primitive(Primitive::Int(i2))) => {
|
|
|
|
i.into_inner() <= *i2 as f64
|
|
|
|
}
|
|
|
|
(Operator::GreaterThanOrEqual, Value::Primitive(Primitive::Int(i2))) => {
|
|
|
|
i.into_inner() >= *i2 as f64
|
|
|
|
}
|
|
|
|
(Operator::Equal, Value::Primitive(Primitive::Int(i2))) => {
|
|
|
|
i.into_inner() == *i2 as f64
|
|
|
|
}
|
|
|
|
(Operator::NotEqual, Value::Primitive(Primitive::Int(i2))) => {
|
|
|
|
i.into_inner() != *i2 as f64
|
|
|
|
}
|
2019-05-17 16:59:25 +00:00
|
|
|
|
|
|
|
_ => false,
|
|
|
|
},
|
2019-05-16 21:43:36 +00:00
|
|
|
Value::Primitive(Primitive::String(s)) => match (op, rhs) {
|
2019-05-18 01:27:31 +00:00
|
|
|
(Operator::Equal, Value::Primitive(Primitive::String(s2))) => s == *s2,
|
|
|
|
(Operator::NotEqual, Value::Primitive(Primitive::String(s2))) => s != *s2,
|
2019-05-16 21:43:36 +00:00
|
|
|
_ => false,
|
|
|
|
},
|
2019-05-16 02:42:44 +00:00
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-05-28 06:45:18 +00:00
|
|
|
|
|
|
|
enum CompareValues {
|
|
|
|
Ints(i64, i64),
|
2019-05-28 07:19:16 +00:00
|
|
|
Floats(OF64, OF64),
|
2019-05-28 06:45:18 +00:00
|
|
|
Bytes(i128, i128),
|
|
|
|
String(String, String),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl CompareValues {
|
|
|
|
fn compare(&self) -> std::cmp::Ordering {
|
|
|
|
match self {
|
|
|
|
CompareValues::Ints(left, right) => left.cmp(right),
|
2019-05-28 07:19:16 +00:00
|
|
|
CompareValues::Floats(left, right) => left.cmp(right),
|
2019-05-28 06:45:18 +00:00
|
|
|
CompareValues::Bytes(left, right) => left.cmp(right),
|
|
|
|
CompareValues::String(left, right) => left.cmp(right),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-24 00:55:31 +00:00
|
|
|
fn coerce_compare(left: &Value, right: &Value) -> Result<CompareValues, (String, String)> {
|
2019-05-28 06:45:18 +00:00
|
|
|
match (left, right) {
|
|
|
|
(Value::Primitive(left), Value::Primitive(right)) => coerce_compare_primitive(left, right),
|
|
|
|
|
2019-06-24 00:55:31 +00:00
|
|
|
_ => Err((left.type_name(), right.type_name())),
|
2019-05-28 06:45:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-24 00:55:31 +00:00
|
|
|
fn coerce_compare_primitive(
|
|
|
|
left: &Primitive,
|
|
|
|
right: &Primitive,
|
|
|
|
) -> Result<CompareValues, (String, String)> {
|
2019-05-28 06:45:18 +00:00
|
|
|
use Primitive::*;
|
|
|
|
|
2019-06-24 00:55:31 +00:00
|
|
|
Ok(match (left, right) {
|
|
|
|
(Int(left), Int(right)) => CompareValues::Ints(*left, *right),
|
|
|
|
(Float(left), Int(right)) => CompareValues::Floats(*left, (*right as f64).into()),
|
|
|
|
(Int(left), Float(right)) => CompareValues::Floats((*left as f64).into(), *right),
|
|
|
|
(Int(left), Bytes(right)) => CompareValues::Bytes(*left as i128, *right as i128),
|
|
|
|
(Bytes(left), Int(right)) => CompareValues::Bytes(*left as i128, *right as i128),
|
|
|
|
(String(left), String(right)) => CompareValues::String(left.clone(), right.clone()),
|
|
|
|
_ => return Err((left.type_name(), right.type_name())),
|
|
|
|
})
|
2019-05-28 06:45:18 +00:00
|
|
|
}
|