improve parsing of values with units (#9190)

closes #9111 

# Description

this pr improves parsing of values with units (`filesizes`, `durations`
and any other **future values**) by:

1. allowing underscores in the value part
```nu
> 42kb          # okay
> 42_sec        # okay
> 1_000_000mib  # okay
> 69k_b         # not okay, underscores not allowed in the unit
```

2. improving error messages involving these values
```nu
> sleep 40-sec

# before
Error: nu::parser::parse_mismatch

  × Parse mismatch during operation.
   ╭─[entry #42:1:1]
 1 │ sleep 40-sec
   ·       ──┬──
   ·         ╰── expected duration with valid units
   ╰────

# now
Error:
  × duration value must be a number
   ╭─[entry #41:1:1]
 1 │ sleep 40-sec
   ·       ─┬─
   ·        ╰── not a number
   ╰────
```

3. unifying parsing of these values. now all of these use one function

# User-Facing Changes

filesizes and durations can now have underscores for readability
This commit is contained in:
mike
2023-05-18 02:54:35 +03:00
committed by GitHub
parent 6a0c88d516
commit 0e4729b203
4 changed files with 195 additions and 190 deletions

View File

@ -1,5 +1,5 @@
use nu_engine::CallExt;
use nu_parser::parse_duration_bytes;
use nu_parser::{parse_unit_value, DURATION_UNIT_GROUPS};
use nu_protocol::{
ast::{Call, CellPath, Expr},
engine::{Command, EngineState, Stack},
@ -409,7 +409,13 @@ fn convert_str_from_unit_to_unit(
}
fn string_to_duration(s: &str, span: Span, value_span: Span) -> Result<i64, ShellError> {
if let Some(expression) = parse_duration_bytes(s.as_bytes(), span) {
if let Some(Ok(expression)) = parse_unit_value(
s.as_bytes(),
span,
DURATION_UNIT_GROUPS,
Type::Duration,
|x| x,
) {
if let Expr::ValueWithUnit(value, unit) = expression.expr {
if let Expr::Int(x) = value.expr {
match unit.item {
@ -445,7 +451,13 @@ fn string_to_unit_duration(
span: Span,
value_span: Span,
) -> Result<(&str, i64), ShellError> {
if let Some(expression) = parse_duration_bytes(s.as_bytes(), span) {
if let Some(Ok(expression)) = parse_unit_value(
s.as_bytes(),
span,
DURATION_UNIT_GROUPS,
Type::Duration,
|x| x,
) {
if let Expr::ValueWithUnit(value, unit) = expression.expr {
if let Expr::Int(x) = value.expr {
match unit.item {