nushell/crates/nu-protocol/src/value.rs

868 lines
28 KiB
Rust
Raw Normal View History

2021-09-01 23:20:53 +02:00
use std::{cell::RefCell, fmt::Debug, rc::Rc};
2021-08-16 00:33:34 +02:00
2021-09-07 00:02:24 +02:00
use crate::ast::{PathMember, RangeInclusion};
2021-09-02 03:29:43 +02:00
use crate::{span, BlockId, Span, Type};
2021-08-16 00:33:34 +02:00
use crate::ShellError;
2021-09-01 23:20:53 +02:00
#[derive(Clone)]
2021-09-03 04:57:18 +02:00
pub struct ValueStream(pub Rc<RefCell<dyn Iterator<Item = Value>>>);
2021-09-01 23:20:53 +02:00
impl ValueStream {
pub fn into_string(self) -> String {
format!(
"[{}]",
2021-09-04 09:59:38 +02:00
self.map(|x| x.into_string())
2021-09-01 23:20:53 +02:00
.collect::<Vec<String>>()
2021-09-04 09:59:38 +02:00
.join(", ")
2021-09-01 23:20:53 +02:00
)
}
2021-09-03 04:57:18 +02:00
pub fn from_stream(input: impl Iterator<Item = Value> + 'static) -> ValueStream {
ValueStream(Rc::new(RefCell::new(input)))
}
2021-09-01 23:20:53 +02:00
}
impl Debug for ValueStream {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ValueStream").finish()
}
}
impl Iterator for ValueStream {
type Item = Value;
fn next(&mut self) -> Option<Self::Item> {
{
let mut iter = self.0.borrow_mut();
iter.next()
}
}
}
pub trait IntoValueStream {
fn into_value_stream(self) -> ValueStream;
}
2021-09-03 04:57:18 +02:00
impl<T> IntoValueStream for T
where
T: Iterator<Item = Value> + 'static,
{
2021-09-01 23:20:53 +02:00
fn into_value_stream(self) -> ValueStream {
2021-09-03 04:57:18 +02:00
ValueStream::from_stream(self)
2021-09-01 23:20:53 +02:00
}
}
#[derive(Clone)]
pub struct RowStream(Rc<RefCell<dyn Iterator<Item = Vec<Value>>>>);
impl RowStream {
pub fn into_string(self, headers: Vec<String>) -> String {
format!(
"[{}]\n[{}]",
headers
.iter()
.map(|x| x.to_string())
.collect::<Vec<String>>()
2021-09-04 09:59:38 +02:00
.join(", "),
self.map(|x| {
x.into_iter()
.map(|x| x.into_string())
.collect::<Vec<String>>()
.join(", ")
})
.collect::<Vec<String>>()
.join("\n")
2021-09-01 23:20:53 +02:00
)
}
}
impl Debug for RowStream {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ValueStream").finish()
}
}
impl Iterator for RowStream {
type Item = Vec<Value>;
fn next(&mut self) -> Option<Self::Item> {
{
let mut iter = self.0.borrow_mut();
iter.next()
}
}
}
pub trait IntoRowStream {
fn into_row_stream(self) -> RowStream;
}
impl IntoRowStream for Vec<Vec<Value>> {
fn into_row_stream(self) -> RowStream {
RowStream(Rc::new(RefCell::new(self.into_iter())))
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Range {
pub from: Value,
pub to: Value,
pub inclusion: RangeInclusion,
}
2021-09-06 06:07:48 +02:00
impl IntoIterator for Range {
type Item = Value;
type IntoIter = RangeIterator;
fn into_iter(self) -> Self::IntoIter {
let span = self.from.span();
RangeIterator::new(self, span)
}
}
pub struct RangeIterator {
curr: Value,
end: Value,
span: Span,
is_end_inclusive: bool,
moves_up: bool,
one: Value,
negative_one: Value,
done: bool,
}
impl RangeIterator {
pub fn new(range: Range, span: Span) -> RangeIterator {
let start = match range.from {
Value::Nothing { .. } => Value::Int { val: 0, span },
x => x,
};
let end = match range.to {
Value::Nothing { .. } => Value::Int {
val: i64::MAX,
span,
},
x => x,
};
RangeIterator {
moves_up: matches!(start.lte(span, &end), Ok(Value::Bool { val: true, .. })),
curr: start,
end,
span,
is_end_inclusive: matches!(range.inclusion, RangeInclusion::Inclusive),
done: false,
one: Value::Int { val: 1, span },
negative_one: Value::Int { val: -1, span },
}
}
}
impl Iterator for RangeIterator {
type Item = Value;
fn next(&mut self) -> Option<Self::Item> {
use std::cmp::Ordering;
if self.done {
return None;
}
let ordering = if matches!(self.end, Value::Nothing { .. }) {
Ordering::Less
} else {
match (&self.curr, &self.end) {
(Value::Int { val: x, .. }, Value::Int { val: y, .. }) => x.cmp(y),
// (Value::Float { val: x, .. }, Value::Float { val: y, .. }) => x.cmp(y),
// (Value::Float { val: x, .. }, Value::Int { val: y, .. }) => x.cmp(y),
// (Value::Int { val: x, .. }, Value::Float { val: y, .. }) => x.cmp(y),
_ => {
self.done = true;
return Some(Value::Error {
error: ShellError::CannotCreateRange(self.span),
});
}
}
};
if self.moves_up
&& (ordering == Ordering::Less || self.is_end_inclusive && ordering == Ordering::Equal)
{
let next_value = self.curr.add(self.span, &self.one);
let mut next = match next_value {
Ok(result) => result,
Err(error) => {
self.done = true;
return Some(Value::Error { error });
}
};
std::mem::swap(&mut self.curr, &mut next);
Some(next)
} else if !self.moves_up
&& (ordering == Ordering::Greater
|| self.is_end_inclusive && ordering == Ordering::Equal)
{
let next_value = self.curr.add(self.span, &self.negative_one);
let mut next = match next_value {
Ok(result) => result,
Err(error) => {
self.done = true;
return Some(Value::Error { error });
}
};
std::mem::swap(&mut self.curr, &mut next);
Some(next)
} else {
None
}
}
}
2021-08-16 00:33:34 +02:00
#[derive(Debug, Clone)]
pub enum Value {
2021-08-28 21:17:30 +02:00
Bool {
val: bool,
span: Span,
},
Int {
val: i64,
span: Span,
},
Range {
val: Box<Range>,
span: Span,
},
2021-08-28 21:17:30 +02:00
Float {
val: f64,
span: Span,
},
String {
val: String,
span: Span,
},
Record {
cols: Vec<String>,
vals: Vec<Value>,
2021-09-04 08:52:28 +02:00
span: Span,
},
ValueStream {
stream: ValueStream,
2021-09-04 08:52:28 +02:00
span: Span,
},
2021-08-28 21:17:30 +02:00
List {
vals: Vec<Value>,
2021-08-28 21:17:30 +02:00
span: Span,
},
Block {
val: BlockId,
span: Span,
},
Nothing {
span: Span,
},
2021-09-06 01:16:27 +02:00
Error {
2021-09-06 06:07:48 +02:00
error: ShellError,
2021-09-06 01:16:27 +02:00
},
2021-08-16 00:33:34 +02:00
}
impl Value {
pub fn as_string(&self) -> Result<String, ShellError> {
match self {
Value::String { val, .. } => Ok(val.to_string()),
_ => Err(ShellError::CantConvert("string".into(), self.span())),
}
}
pub fn span(&self) -> Span {
match self {
Value::Bool { span, .. } => *span,
Value::Int { span, .. } => *span,
Value::Float { span, .. } => *span,
Value::Range { span, .. } => *span,
2021-08-16 00:33:34 +02:00
Value::String { span, .. } => *span,
Value::Record { span, .. } => *span,
2021-08-16 00:33:34 +02:00
Value::List { span, .. } => *span,
Value::Block { span, .. } => *span,
2021-09-04 08:52:28 +02:00
Value::ValueStream { span, .. } => *span,
2021-08-16 00:33:34 +02:00
Value::Nothing { span, .. } => *span,
2021-09-06 01:16:27 +02:00
Value::Error { .. } => Span::unknown(),
2021-08-16 00:33:34 +02:00
}
}
pub fn with_span(mut self, new_span: Span) -> Value {
match &mut self {
Value::Bool { span, .. } => *span = new_span,
Value::Int { span, .. } => *span = new_span,
Value::Float { span, .. } => *span = new_span,
Value::Range { span, .. } => *span = new_span,
2021-08-16 00:33:34 +02:00
Value::String { span, .. } => *span = new_span,
Value::Record { span, .. } => *span = new_span,
2021-09-04 08:52:28 +02:00
Value::ValueStream { span, .. } => *span = new_span,
2021-08-16 00:33:34 +02:00
Value::List { span, .. } => *span = new_span,
Value::Block { span, .. } => *span = new_span,
Value::Nothing { span, .. } => *span = new_span,
2021-09-06 01:16:27 +02:00
Value::Error { .. } => {}
2021-08-16 00:33:34 +02:00
}
self
}
pub fn get_type(&self) -> Type {
match self {
Value::Bool { .. } => Type::Bool,
Value::Int { .. } => Type::Int,
Value::Float { .. } => Type::Float,
Value::Range { .. } => Type::Range,
2021-08-16 00:33:34 +02:00
Value::String { .. } => Type::String,
Value::Record { cols, vals, .. } => {
Type::Record(cols.clone(), vals.iter().map(|x| x.get_type()).collect())
}
2021-08-16 00:33:34 +02:00
Value::List { .. } => Type::List(Box::new(Type::Unknown)), // FIXME
Value::Nothing { .. } => Type::Nothing,
Value::Block { .. } => Type::Block,
2021-09-04 08:52:28 +02:00
Value::ValueStream { .. } => Type::ValueStream,
2021-09-06 01:16:27 +02:00
Value::Error { .. } => Type::Error,
2021-08-16 00:33:34 +02:00
}
}
2021-09-01 23:20:53 +02:00
pub fn into_string(self) -> String {
match self {
Value::Bool { val, .. } => val.to_string(),
Value::Int { val, .. } => val.to_string(),
Value::Float { val, .. } => val.to_string(),
Value::Range { val, .. } => {
let vals: Vec<i64> = match (&val.from, &val.to) {
(Value::Int { val: from, .. }, Value::Int { val: to, .. }) => {
match val.inclusion {
RangeInclusion::Inclusive => (*from..=*to).collect(),
RangeInclusion::RightExclusive => (*from..*to).collect(),
}
}
_ => Vec::new(),
};
format!(
"range: [{}]",
vals.iter()
.map(|x| x.to_string())
.collect::<Vec<String>>()
2021-09-05 00:40:15 +02:00
.join(", ")
)
2021-09-05 00:35:08 +02:00
}
2021-09-01 23:20:53 +02:00
Value::String { val, .. } => val,
2021-09-04 08:52:28 +02:00
Value::ValueStream { stream, .. } => stream.into_string(),
Value::List { vals: val, .. } => format!(
2021-09-07 00:02:24 +02:00
"[{}]",
val.into_iter()
.map(|x| x.into_string())
.collect::<Vec<_>>()
.join(", ")
),
Value::Record { cols, vals, .. } => format!(
"{{{}}}",
cols.iter()
.zip(vals.iter())
.map(|(x, y)| format!("{}: {}", x, y.clone().into_string()))
2021-09-07 00:02:24 +02:00
.collect::<Vec<_>>()
.join(", ")
2021-09-07 00:02:24 +02:00
),
2021-09-01 23:20:53 +02:00
Value::Block { val, .. } => format!("<Block {}>", val),
2021-09-02 03:29:43 +02:00
Value::Nothing { .. } => String::new(),
2021-09-06 06:07:48 +02:00
Value::Error { error } => format!("{:?}", error),
2021-09-01 23:20:53 +02:00
}
}
2021-09-03 04:15:01 +02:00
pub fn nothing() -> Value {
Value::Nothing {
span: Span::unknown(),
}
}
2021-09-07 00:02:24 +02:00
pub fn follow_cell_path(self, column_path: &[PathMember]) -> Result<Value, ShellError> {
2021-09-07 00:02:24 +02:00
let mut current = self;
for member in column_path {
// FIXME: this uses a few extra clones for simplicity, but there may be a way
// to traverse the path without them
match member {
PathMember::Int {
val: count,
span: origin_span,
} => {
// Treat a numeric path member as `nth <val>`
match &mut current {
Value::List { vals: val, .. } => {
2021-09-07 00:02:24 +02:00
if let Some(item) = val.get(*count) {
current = item.clone();
} else {
return Err(ShellError::AccessBeyondEnd(val.len(), *origin_span));
}
}
Value::ValueStream { stream, .. } => {
if let Some(item) = stream.nth(*count) {
current = item;
} else {
return Err(ShellError::AccessBeyondEndOfStream(*origin_span));
}
}
x => {
return Err(ShellError::IncompatiblePathAccess(
format!("{}", x.get_type()),
*origin_span,
))
}
}
}
PathMember::String {
val: column_name,
2021-09-07 00:02:24 +02:00
span: origin_span,
} => match &mut current {
Value::Record { cols, vals, .. } => {
2021-09-07 00:02:24 +02:00
let mut found = false;
for col in cols.iter().zip(vals.iter()) {
if col.0 == column_name {
current = col.1.clone();
2021-09-07 00:02:24 +02:00
found = true;
break;
}
}
if !found {
return Err(ShellError::CantFindColumn(*origin_span));
}
}
Value::List { vals, span } => {
let mut output = vec![];
for val in vals {
if let Value::Record { cols, vals, .. } = val {
for col in cols.iter().enumerate() {
if col.1 == column_name {
output.push(vals[col.0].clone());
}
2021-09-07 00:02:24 +02:00
}
}
}
current = Value::List {
vals: output,
span: *span,
};
2021-09-07 00:02:24 +02:00
}
x => {
return Err(ShellError::IncompatiblePathAccess(
format!("{}", x.get_type()),
*origin_span,
))
}
},
}
}
Ok(current)
}
2021-08-16 00:33:34 +02:00
}
impl PartialEq for Value {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Value::Bool { val: lhs, .. }, Value::Bool { val: rhs, .. }) => lhs == rhs,
(Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => lhs == rhs,
(Value::Float { val: lhs, .. }, Value::Float { val: rhs, .. }) => lhs == rhs,
(Value::String { val: lhs, .. }, Value::String { val: rhs, .. }) => lhs == rhs,
(Value::Block { val: b1, .. }, Value::Block { val: b2, .. }) => b1 == b2,
_ => false,
}
}
}
impl Value {
pub fn add(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> {
2021-09-02 03:29:43 +02:00
let span = span(&[self.span(), rhs.span()]);
2021-08-16 00:33:34 +02:00
match (self, rhs) {
(Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Int {
val: lhs + rhs,
span,
}),
(Value::Int { val: lhs, .. }, Value::Float { val: rhs, .. }) => Ok(Value::Float {
val: *lhs as f64 + *rhs,
span,
}),
(Value::Float { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Float {
val: *lhs + *rhs as f64,
span,
}),
(Value::Float { val: lhs, .. }, Value::Float { val: rhs, .. }) => Ok(Value::Float {
val: lhs + rhs,
span,
}),
(Value::String { val: lhs, .. }, Value::String { val: rhs, .. }) => Ok(Value::String {
val: lhs.to_string() + rhs,
span,
}),
_ => Err(ShellError::OperatorMismatch {
op_span: op,
lhs_ty: self.get_type(),
lhs_span: self.span(),
rhs_ty: rhs.get_type(),
rhs_span: rhs.span(),
}),
}
}
2021-08-25 21:29:36 +02:00
pub fn sub(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> {
2021-09-02 03:29:43 +02:00
let span = span(&[self.span(), rhs.span()]);
2021-08-25 21:29:36 +02:00
match (self, rhs) {
(Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Int {
val: lhs - rhs,
span,
}),
(Value::Int { val: lhs, .. }, Value::Float { val: rhs, .. }) => Ok(Value::Float {
val: *lhs as f64 - *rhs,
span,
}),
(Value::Float { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Float {
val: *lhs - *rhs as f64,
span,
}),
(Value::Float { val: lhs, .. }, Value::Float { val: rhs, .. }) => Ok(Value::Float {
val: lhs - rhs,
span,
}),
_ => Err(ShellError::OperatorMismatch {
op_span: op,
lhs_ty: self.get_type(),
lhs_span: self.span(),
rhs_ty: rhs.get_type(),
rhs_span: rhs.span(),
}),
}
}
pub fn mul(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> {
2021-09-02 03:29:43 +02:00
let span = span(&[self.span(), rhs.span()]);
2021-08-25 21:29:36 +02:00
match (self, rhs) {
(Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Int {
val: lhs * rhs,
span,
}),
(Value::Int { val: lhs, .. }, Value::Float { val: rhs, .. }) => Ok(Value::Float {
val: *lhs as f64 * *rhs,
span,
}),
(Value::Float { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Float {
val: *lhs * *rhs as f64,
span,
}),
(Value::Float { val: lhs, .. }, Value::Float { val: rhs, .. }) => Ok(Value::Float {
val: lhs * rhs,
span,
}),
_ => Err(ShellError::OperatorMismatch {
op_span: op,
lhs_ty: self.get_type(),
lhs_span: self.span(),
rhs_ty: rhs.get_type(),
rhs_span: rhs.span(),
}),
}
}
pub fn div(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> {
2021-09-02 03:29:43 +02:00
let span = span(&[self.span(), rhs.span()]);
2021-08-25 21:29:36 +02:00
match (self, rhs) {
(Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => {
if *rhs != 0 {
if lhs % rhs == 0 {
Ok(Value::Int {
val: lhs / rhs,
span,
})
} else {
Ok(Value::Float {
val: (*lhs as f64) / (*rhs as f64),
span,
})
}
2021-08-25 21:29:36 +02:00
} else {
Err(ShellError::DivisionByZero(op))
}
}
(Value::Int { val: lhs, .. }, Value::Float { val: rhs, .. }) => {
if *rhs != 0.0 {
Ok(Value::Float {
val: *lhs as f64 / *rhs,
span,
})
} else {
Err(ShellError::DivisionByZero(op))
}
}
(Value::Float { val: lhs, .. }, Value::Int { val: rhs, .. }) => {
if *rhs != 0 {
Ok(Value::Float {
val: *lhs / *rhs as f64,
span,
})
} else {
Err(ShellError::DivisionByZero(op))
}
}
(Value::Float { val: lhs, .. }, Value::Float { val: rhs, .. }) => {
if *rhs != 0.0 {
Ok(Value::Float {
val: lhs / rhs,
span,
})
} else {
Err(ShellError::DivisionByZero(op))
}
}
_ => Err(ShellError::OperatorMismatch {
op_span: op,
lhs_ty: self.get_type(),
lhs_span: self.span(),
rhs_ty: rhs.get_type(),
rhs_span: rhs.span(),
}),
}
}
pub fn lt(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> {
2021-09-02 03:29:43 +02:00
let span = span(&[self.span(), rhs.span()]);
2021-08-25 21:29:36 +02:00
match (self, rhs) {
(Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Bool {
val: lhs < rhs,
span,
}),
(Value::Int { val: lhs, .. }, Value::Float { val: rhs, .. }) => Ok(Value::Bool {
val: (*lhs as f64) < *rhs,
span,
}),
(Value::Float { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Bool {
val: *lhs < *rhs as f64,
span,
}),
(Value::Float { val: lhs, .. }, Value::Float { val: rhs, .. }) => Ok(Value::Bool {
val: lhs < rhs,
span,
}),
_ => Err(ShellError::OperatorMismatch {
op_span: op,
lhs_ty: self.get_type(),
lhs_span: self.span(),
rhs_ty: rhs.get_type(),
rhs_span: rhs.span(),
}),
}
}
pub fn lte(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> {
2021-09-02 03:29:43 +02:00
let span = span(&[self.span(), rhs.span()]);
2021-08-25 21:29:36 +02:00
match (self, rhs) {
(Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Bool {
val: lhs <= rhs,
span,
}),
(Value::Int { val: lhs, .. }, Value::Float { val: rhs, .. }) => Ok(Value::Bool {
val: (*lhs as f64) <= *rhs,
span,
}),
(Value::Float { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Bool {
val: *lhs <= *rhs as f64,
span,
}),
(Value::Float { val: lhs, .. }, Value::Float { val: rhs, .. }) => Ok(Value::Bool {
val: lhs <= rhs,
span,
}),
_ => Err(ShellError::OperatorMismatch {
op_span: op,
lhs_ty: self.get_type(),
lhs_span: self.span(),
rhs_ty: rhs.get_type(),
rhs_span: rhs.span(),
}),
}
}
pub fn gt(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> {
2021-09-02 03:29:43 +02:00
let span = span(&[self.span(), rhs.span()]);
2021-08-25 21:29:36 +02:00
match (self, rhs) {
(Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Bool {
val: lhs > rhs,
span,
}),
(Value::Int { val: lhs, .. }, Value::Float { val: rhs, .. }) => Ok(Value::Bool {
val: (*lhs as f64) > *rhs,
span,
}),
(Value::Float { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Bool {
val: *lhs > *rhs as f64,
span,
}),
(Value::Float { val: lhs, .. }, Value::Float { val: rhs, .. }) => Ok(Value::Bool {
val: lhs > rhs,
span,
}),
_ => Err(ShellError::OperatorMismatch {
op_span: op,
lhs_ty: self.get_type(),
lhs_span: self.span(),
rhs_ty: rhs.get_type(),
rhs_span: rhs.span(),
}),
}
}
pub fn gte(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> {
2021-09-02 03:29:43 +02:00
let span = span(&[self.span(), rhs.span()]);
2021-08-25 21:29:36 +02:00
match (self, rhs) {
(Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Bool {
val: lhs >= rhs,
span,
}),
(Value::Int { val: lhs, .. }, Value::Float { val: rhs, .. }) => Ok(Value::Bool {
val: (*lhs as f64) >= *rhs,
span,
}),
(Value::Float { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Bool {
val: *lhs >= *rhs as f64,
span,
}),
(Value::Float { val: lhs, .. }, Value::Float { val: rhs, .. }) => Ok(Value::Bool {
val: lhs >= rhs,
span,
}),
_ => Err(ShellError::OperatorMismatch {
op_span: op,
lhs_ty: self.get_type(),
lhs_span: self.span(),
rhs_ty: rhs.get_type(),
rhs_span: rhs.span(),
}),
}
}
pub fn eq(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> {
2021-09-02 03:29:43 +02:00
let span = span(&[self.span(), rhs.span()]);
2021-08-25 21:29:36 +02:00
match (self, rhs) {
(Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Bool {
val: lhs == rhs,
span,
}),
(Value::String { val: lhs, .. }, Value::String { val: rhs, .. }) => Ok(Value::Bool {
val: lhs == rhs,
span,
}),
// FIXME: these should consider machine epsilon
(Value::Int { val: lhs, .. }, Value::Float { val: rhs, .. }) => Ok(Value::Bool {
val: (*lhs as f64) == *rhs,
span,
}),
// FIXME: these should consider machine epsilon
(Value::Float { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Bool {
val: *lhs == *rhs as f64,
span,
}),
// FIXME: these should consider machine epsilon
(Value::Float { val: lhs, .. }, Value::Float { val: rhs, .. }) => Ok(Value::Bool {
val: lhs == rhs,
span,
}),
(Value::List { vals: lhs, .. }, Value::List { vals: rhs, .. }) => Ok(Value::Bool {
2021-09-04 08:52:28 +02:00
val: lhs == rhs,
span,
}),
(
Value::Record {
vals: lhs,
cols: lhs_headers,
2021-09-04 08:52:28 +02:00
..
},
Value::Record {
vals: rhs,
cols: rhs_headers,
2021-09-04 08:52:28 +02:00
..
},
) => Ok(Value::Bool {
val: lhs_headers == rhs_headers && lhs == rhs,
span,
}),
2021-08-25 21:29:36 +02:00
_ => Err(ShellError::OperatorMismatch {
op_span: op,
lhs_ty: self.get_type(),
lhs_span: self.span(),
rhs_ty: rhs.get_type(),
rhs_span: rhs.span(),
}),
}
}
pub fn ne(&self, op: Span, rhs: &Value) -> Result<Value, ShellError> {
2021-09-02 03:29:43 +02:00
let span = span(&[self.span(), rhs.span()]);
2021-08-25 21:29:36 +02:00
match (self, rhs) {
(Value::Int { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Bool {
val: lhs != rhs,
span,
}),
(Value::String { val: lhs, .. }, Value::String { val: rhs, .. }) => Ok(Value::Bool {
val: lhs != rhs,
span,
}),
// FIXME: these should consider machine epsilon
(Value::Int { val: lhs, .. }, Value::Float { val: rhs, .. }) => Ok(Value::Bool {
val: (*lhs as f64) != *rhs,
span,
}),
// FIXME: these should consider machine epsilon
(Value::Float { val: lhs, .. }, Value::Int { val: rhs, .. }) => Ok(Value::Bool {
val: *lhs != *rhs as f64,
span,
}),
// FIXME: these should consider machine epsilon
(Value::Float { val: lhs, .. }, Value::Float { val: rhs, .. }) => Ok(Value::Bool {
val: lhs != rhs,
span,
}),
(Value::List { vals: lhs, .. }, Value::List { vals: rhs, .. }) => Ok(Value::Bool {
2021-09-04 08:52:28 +02:00
val: lhs != rhs,
span,
}),
(
Value::Record {
vals: lhs,
cols: lhs_headers,
2021-09-04 08:52:28 +02:00
..
},
Value::Record {
vals: rhs,
cols: rhs_headers,
2021-09-04 08:52:28 +02:00
..
},
) => Ok(Value::Bool {
val: lhs_headers != rhs_headers || lhs != rhs,
span,
}),
2021-08-25 21:29:36 +02:00
_ => Err(ShellError::OperatorMismatch {
op_span: op,
lhs_ty: self.get_type(),
lhs_span: self.span(),
rhs_ty: rhs.get_type(),
rhs_span: rhs.span(),
}),
}
}
2021-08-16 00:33:34 +02:00
}