make the pattern-matcher and eval engine use the same unit computation (#8973)

# Description
this pr adresses
[this](7413ef2824/crates/nu-protocol/src/engine/pattern_match.rs (L149))
'fix me'
This commit is contained in:
mike 2023-05-12 20:18:11 +03:00 committed by GitHub
parent 6cbd42974b
commit 2254805a6d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 134 additions and 172 deletions

View File

@ -1231,128 +1231,7 @@ pub fn eval_variable(
} }
fn compute(size: i64, unit: Unit, span: Span) -> Value { fn compute(size: i64, unit: Unit, span: Span) -> Value {
match unit { unit.to_value(size, span)
Unit::Byte => Value::Filesize { val: size, span },
Unit::Kilobyte => Value::Filesize {
val: size * 1000,
span,
},
Unit::Megabyte => Value::Filesize {
val: size * 1000 * 1000,
span,
},
Unit::Gigabyte => Value::Filesize {
val: size * 1000 * 1000 * 1000,
span,
},
Unit::Terabyte => Value::Filesize {
val: size * 1000 * 1000 * 1000 * 1000,
span,
},
Unit::Petabyte => Value::Filesize {
val: size * 1000 * 1000 * 1000 * 1000 * 1000,
span,
},
Unit::Exabyte => Value::Filesize {
val: size * 1000 * 1000 * 1000 * 1000 * 1000 * 1000,
span,
},
Unit::Zettabyte => Value::Filesize {
val: size * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000,
span,
},
Unit::Kibibyte => Value::Filesize {
val: size * 1024,
span,
},
Unit::Mebibyte => Value::Filesize {
val: size * 1024 * 1024,
span,
},
Unit::Gibibyte => Value::Filesize {
val: size * 1024 * 1024 * 1024,
span,
},
Unit::Tebibyte => Value::Filesize {
val: size * 1024 * 1024 * 1024 * 1024,
span,
},
Unit::Pebibyte => Value::Filesize {
val: size * 1024 * 1024 * 1024 * 1024 * 1024,
span,
},
Unit::Exbibyte => Value::Filesize {
val: size * 1024 * 1024 * 1024 * 1024 * 1024 * 1024,
span,
},
Unit::Zebibyte => Value::Filesize {
val: size * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024,
span,
},
Unit::Nanosecond => Value::Duration { val: size, span },
Unit::Microsecond => Value::Duration {
val: size * 1000,
span,
},
Unit::Millisecond => Value::Duration {
val: size * 1000 * 1000,
span,
},
Unit::Second => Value::Duration {
val: size * 1000 * 1000 * 1000,
span,
},
Unit::Minute => match size.checked_mul(1000 * 1000 * 1000 * 60) {
Some(val) => Value::Duration { val, span },
None => Value::Error {
error: Box::new(ShellError::GenericError(
"duration too large".into(),
"duration too large".into(),
Some(span),
None,
Vec::new(),
)),
},
},
Unit::Hour => match size.checked_mul(1000 * 1000 * 1000 * 60 * 60) {
Some(val) => Value::Duration { val, span },
None => Value::Error {
error: Box::new(ShellError::GenericError(
"duration too large".into(),
"duration too large".into(),
Some(span),
None,
Vec::new(),
)),
},
},
Unit::Day => match size.checked_mul(1000 * 1000 * 1000 * 60 * 60 * 24) {
Some(val) => Value::Duration { val, span },
None => Value::Error {
error: Box::new(ShellError::GenericError(
"duration too large".into(),
"duration too large".into(),
Some(span),
None,
Vec::new(),
)),
},
},
Unit::Week => match size.checked_mul(1000 * 1000 * 1000 * 60 * 60 * 24 * 7) {
Some(val) => Value::Duration { val, span },
None => Value::Error {
error: Box::new(ShellError::GenericError(
"duration too large".into(),
"duration too large".into(),
Some(span),
None,
Vec::new(),
)),
},
},
}
} }
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]

View File

@ -1,6 +1,6 @@
use crate::{ use crate::{
ast::{Expr, MatchPattern, Pattern, RangeInclusion}, ast::{Expr, MatchPattern, Pattern, RangeInclusion},
Span, Unit, Value, VarId, Span, Value, VarId,
}; };
pub trait Matcher { pub trait Matcher {
@ -145,55 +145,10 @@ impl Matcher for Pattern {
} }
} }
Expr::ValueWithUnit(amount, unit) => { Expr::ValueWithUnit(amount, unit) => {
if let Value::Filesize { val, .. } = &value { let span = unit.span;
// FIXME: we probably want this math in one place that both the
// pattern matcher and the eval engine can get to it if let Expr::Int(size) = amount.expr {
match &amount.expr { &unit.item.to_value(size, span) == value
Expr::Int(amount) => match &unit.item {
Unit::Byte => amount == val,
Unit::Kilobyte => *val == amount * 1000,
Unit::Megabyte => *val == amount * 1000 * 1000,
Unit::Gigabyte => *val == amount * 1000 * 1000 * 1000,
Unit::Petabyte => *val == amount * 1000 * 1000 * 1000 * 1000,
Unit::Exabyte => {
*val == amount * 1000 * 1000 * 1000 * 1000 * 1000
}
Unit::Zettabyte => {
*val == amount * 1000 * 1000 * 1000 * 1000 * 1000 * 1000
}
Unit::Kibibyte => *val == amount * 1024,
Unit::Mebibyte => *val == amount * 1024 * 1024,
Unit::Gibibyte => *val == amount * 1024 * 1024 * 1024,
Unit::Pebibyte => *val == amount * 1024 * 1024 * 1024 * 1024,
Unit::Exbibyte => {
*val == amount * 1024 * 1024 * 1024 * 1024 * 1024
}
Unit::Zebibyte => {
*val == amount * 1024 * 1024 * 1024 * 1024 * 1024 * 1024
}
_ => false,
},
_ => false,
}
} else if let Value::Duration { val, .. } = &value {
// FIXME: we probably want this math in one place that both the
// pattern matcher and the eval engine can get to it
match &amount.expr {
Expr::Int(amount) => match &unit.item {
Unit::Nanosecond => val == amount,
Unit::Microsecond => *val == amount * 1000,
Unit::Millisecond => *val == amount * 1000 * 1000,
Unit::Second => *val == amount * 1000 * 1000 * 1000,
Unit::Minute => *val == amount * 1000 * 1000 * 1000 * 60,
Unit::Hour => *val == amount * 1000 * 1000 * 1000 * 60 * 60,
Unit::Day => *val == amount * 1000 * 1000 * 1000 * 60 * 60 * 24,
Unit::Week => {
*val == amount * 1000 * 1000 * 1000 * 60 * 60 * 24 * 7
}
_ => false,
},
_ => false,
}
} else { } else {
false false
} }

View File

@ -1,3 +1,4 @@
use crate::{ShellError, Span, Value};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
@ -31,3 +32,130 @@ pub enum Unit {
Day, Day,
Week, Week,
} }
impl Unit {
pub fn to_value(&self, size: i64, span: Span) -> Value {
match self {
Unit::Byte => Value::Filesize { val: size, span },
Unit::Kilobyte => Value::Filesize {
val: size * 1000,
span,
},
Unit::Megabyte => Value::Filesize {
val: size * 1000 * 1000,
span,
},
Unit::Gigabyte => Value::Filesize {
val: size * 1000 * 1000 * 1000,
span,
},
Unit::Terabyte => Value::Filesize {
val: size * 1000 * 1000 * 1000 * 1000,
span,
},
Unit::Petabyte => Value::Filesize {
val: size * 1000 * 1000 * 1000 * 1000 * 1000,
span,
},
Unit::Exabyte => Value::Filesize {
val: size * 1000 * 1000 * 1000 * 1000 * 1000 * 1000,
span,
},
Unit::Zettabyte => Value::Filesize {
val: size * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000,
span,
},
Unit::Kibibyte => Value::Filesize {
val: size * 1024,
span,
},
Unit::Mebibyte => Value::Filesize {
val: size * 1024 * 1024,
span,
},
Unit::Gibibyte => Value::Filesize {
val: size * 1024 * 1024 * 1024,
span,
},
Unit::Tebibyte => Value::Filesize {
val: size * 1024 * 1024 * 1024 * 1024,
span,
},
Unit::Pebibyte => Value::Filesize {
val: size * 1024 * 1024 * 1024 * 1024 * 1024,
span,
},
Unit::Exbibyte => Value::Filesize {
val: size * 1024 * 1024 * 1024 * 1024 * 1024 * 1024,
span,
},
Unit::Zebibyte => Value::Filesize {
val: size * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024,
span,
},
Unit::Nanosecond => Value::Duration { val: size, span },
Unit::Microsecond => Value::Duration {
val: size * 1000,
span,
},
Unit::Millisecond => Value::Duration {
val: size * 1000 * 1000,
span,
},
Unit::Second => Value::Duration {
val: size * 1000 * 1000 * 1000,
span,
},
Unit::Minute => match size.checked_mul(1000 * 1000 * 1000 * 60) {
Some(val) => Value::Duration { val, span },
None => Value::Error {
error: Box::new(ShellError::GenericError(
"duration too large".into(),
"duration too large".into(),
Some(span),
None,
Vec::new(),
)),
},
},
Unit::Hour => match size.checked_mul(1000 * 1000 * 1000 * 60 * 60) {
Some(val) => Value::Duration { val, span },
None => Value::Error {
error: Box::new(ShellError::GenericError(
"duration too large".into(),
"duration too large".into(),
Some(span),
None,
Vec::new(),
)),
},
},
Unit::Day => match size.checked_mul(1000 * 1000 * 1000 * 60 * 60 * 24) {
Some(val) => Value::Duration { val, span },
None => Value::Error {
error: Box::new(ShellError::GenericError(
"duration too large".into(),
"duration too large".into(),
Some(span),
None,
Vec::new(),
)),
},
},
Unit::Week => match size.checked_mul(1000 * 1000 * 1000 * 60 * 60 * 24 * 7) {
Some(val) => Value::Duration { val, span },
None => Value::Error {
error: Box::new(ShellError::GenericError(
"duration too large".into(),
"duration too large".into(),
Some(span),
None,
Vec::new(),
)),
},
},
}
}
}