Repository: nushell/nushell
File: crates/nu-parser/src/parser.rs (Rust)

Code before:
        let str = String::from_utf8_lossy(&binary_value).to_string();

        match decode_with_base(&str, base, min_digits_per_byte) {
            Ok(v) => return Expression::new(working_set, Expr::Binary(v), span, Type::Binary),
            Err(help) => {
                working_set.error(ParseError::InvalidBinaryString(span, help.to_string()));
                return garbage(working_set, span);
            }
        }
    }

    working_set.error(ParseError::Expected("binary", span));
    garbage(working_set, span)
}

fn decode_with_base(s: &str, base: u32, digits_per_byte: usize) -> Result<Vec<u8>, &str> {
    s.chars()
        .chunks(digits_per_byte)
        .into_iter()
        .map(|chunk| {
            let str: String = chunk.collect();
            u8::from_str_radix(&str, base).map_err(|_| match base {
                2 => "binary strings may contain only 0 or 1.",
                8 => "octal strings must have a length that is a multiple of three and contain values between 0o000 and 0o377.",
                16 => "hexadecimal strings may contain only the characters 0–9 and A–F.",
                _ => "", // radix other than 2, 8, or 16 is an invalid radix
            })
        })
        .collect()
}

fn strip_underscores(token: &[u8]) -> String {
    String::from_utf8_lossy(token)
        .chars()
        .filter(|c| *c != '_')
        .collect()
}

pub fn parse_int(working_set: &mut StateWorkingSet, span: Span) -> Expression {
    let token = working_set.get_span_contents(span);

    fn extract_int(
        working_set: &mut StateWorkingSet,
        token: &str,
        span: Span,
        radix: u32,
    ) -> Expression {
        // Parse as a u64, then cast to i64, otherwise, for numbers like "0xffffffffffffffef",
        // you'll get `Error parsing hex string: number too large to fit in target type`.
        if let Ok(num) = u64::from_str_radix(token, radix).map(|val| val as i64) {
            Expression::new(working_set, Expr::Int(num), span, Type::Int)

Review comment (bug):
Thanks for elaborating in the messages.

Defensively you can throw the text of the comment with something like `INTERNAL ERROR:` into the fall through arm. If there is ever something going wrong being loud about it can be helpful even if it is vanishingly likely to break.

Code after:
            };
        }

        let str = String::from_utf8_lossy(&binary_value).to_string();

        match decode_with_base(&str, base, min_digits_per_byte) {
            Ok(v) => return Expression::new(working_set, Expr::Binary(v), span, Type::Binary),
            Err(help) => {
                working_set.error(ParseError::InvalidBinaryString(span, help.to_string()));
                return garbage(working_set, span);
            }
        }
    }

    working_set.error(ParseError::Expected("binary", span));
    garbage(working_set, span)
}

fn decode_with_base(s: &str, base: u32, digits_per_byte: usize) -> Result<Vec<u8>, &str> {
    s.chars()
        .chunks(digits_per_byte)
        .into_iter()
        .map(|chunk| {
            let str: String = chunk.collect();
            u8::from_str_radix(&str, base).map_err(|_| match base {
                2 => "binary strings may contain only 0 or 1.",
                8 => "octal strings must have a length that is a multiple of three and contain values between 0o000 and 0o377.",
                16 => "hexadecimal strings may contain only the characters 0–9 and A–F.",
                _ => "internal error: radix other than 2, 8, or 16 is not allowed."
            })
        })
        .collect()
}

fn strip_underscores(token: &[u8]) -> String {
    String::from_utf8_lossy(token)
        .chars()
        .filter(|c| *c != '_')
        .collect()
}

pub fn parse_int(working_set: &mut StateWorkingSet, span: Span) -> Expression {
    let token = working_set.get_span_contents(span);

    fn extract_int(
        working_set: &mut StateWorkingSet,
        token: &str,
        span: Span,
        radix: u32,
    ) -> Expression {
        // Parse as a u64, then cast to i64, otherwise, for numbers like "0xffffffffffffffef",