mirror of
https://github.com/nushell/nushell
synced 2025-01-14 14:14:13 +00:00
Support binary literals with binary format (#5149)
* 4924 Support binary literals with binary format * 4924 Support automatic padding for binary literals
This commit is contained in:
parent
625e807a35
commit
a30930324d
2 changed files with 99 additions and 21 deletions
|
@ -1074,26 +1074,40 @@ pub fn parse_binary(
|
||||||
working_set: &mut StateWorkingSet,
|
working_set: &mut StateWorkingSet,
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> (Expression, Option<ParseError>) {
|
) -> (Expression, Option<ParseError>) {
|
||||||
pub fn decode_hex(s: &str) -> Result<Vec<u8>, ParseIntError> {
|
let (hex_value, err) = parse_binary_with_base(working_set, span, 16, 2, b"0x[", b"]");
|
||||||
(0..s.len())
|
if err.is_some() {
|
||||||
.step_by(2)
|
return parse_binary_with_base(working_set, span, 2, 8, b"0b[", b"]");
|
||||||
.map(|i| u8::from_str_radix(&s[i..i + 2], 16))
|
|
||||||
.collect()
|
|
||||||
}
|
}
|
||||||
|
(hex_value, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_binary_with_base(
|
||||||
|
working_set: &mut StateWorkingSet,
|
||||||
|
span: Span,
|
||||||
|
base: u32,
|
||||||
|
min_digits_per_byte: usize,
|
||||||
|
prefix: &[u8],
|
||||||
|
suffix: &[u8],
|
||||||
|
) -> (Expression, Option<ParseError>) {
|
||||||
let token = working_set.get_span_contents(span);
|
let token = working_set.get_span_contents(span);
|
||||||
|
|
||||||
if let Some(token) = token.strip_prefix(b"0x[") {
|
if let Some(token) = token.strip_prefix(prefix) {
|
||||||
if let Some(token) = token.strip_suffix(b"]") {
|
if let Some(token) = token.strip_suffix(suffix) {
|
||||||
let (lexed, err) = lex(token, span.start + 3, &[b',', b'\r', b'\n'], &[], true);
|
let (lexed, err) = lex(
|
||||||
|
token,
|
||||||
|
span.start + prefix.len(),
|
||||||
|
&[b',', b'\r', b'\n'],
|
||||||
|
&[],
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
let mut hex_value = vec![];
|
let mut binary_value = vec![];
|
||||||
for token in lexed {
|
for token in lexed {
|
||||||
match token.contents {
|
match token.contents {
|
||||||
TokenContents::Item => {
|
TokenContents::Item => {
|
||||||
let contents = working_set.get_span_contents(token.span);
|
let contents = working_set.get_span_contents(token.span);
|
||||||
|
|
||||||
hex_value.extend_from_slice(contents);
|
binary_value.extend_from_slice(contents);
|
||||||
}
|
}
|
||||||
TokenContents::Pipe => {
|
TokenContents::Pipe => {
|
||||||
return (
|
return (
|
||||||
|
@ -1105,20 +1119,21 @@ pub fn parse_binary(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if hex_value.len() % 2 != 0 {
|
let required_padding = (min_digits_per_byte - binary_value.len() % min_digits_per_byte)
|
||||||
return (
|
% min_digits_per_byte;
|
||||||
garbage(span),
|
|
||||||
Some(ParseError::IncorrectValue(
|
if required_padding != 0 {
|
||||||
"incomplete binary".into(),
|
binary_value = {
|
||||||
span,
|
let mut tail = binary_value;
|
||||||
"number of binary digits needs to be a multiple of 2".into(),
|
let mut binary_value: Vec<u8> = vec![b'0'; required_padding];
|
||||||
)),
|
binary_value.append(&mut tail);
|
||||||
);
|
binary_value
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
let str = String::from_utf8_lossy(&hex_value).to_string();
|
let str = String::from_utf8_lossy(&binary_value).to_string();
|
||||||
|
|
||||||
match decode_hex(&str) {
|
match decode_with_base(&str, base, min_digits_per_byte) {
|
||||||
Ok(v) => {
|
Ok(v) => {
|
||||||
return (
|
return (
|
||||||
Expression {
|
Expression {
|
||||||
|
@ -1149,6 +1164,13 @@ pub fn parse_binary(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn decode_with_base(s: &str, base: u32, digits_per_byte: usize) -> Result<Vec<u8>, ParseIntError> {
|
||||||
|
(0..s.len())
|
||||||
|
.step_by(digits_per_byte)
|
||||||
|
.map(|i| u8::from_str_radix(&s[i..i + digits_per_byte], base))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn parse_int(token: &[u8], span: Span) -> (Expression, Option<ParseError>) {
|
pub fn parse_int(token: &[u8], span: Span) -> (Expression, Option<ParseError>) {
|
||||||
if let Some(token) = token.strip_prefix(b"0x") {
|
if let Some(token) = token.strip_prefix(b"0x") {
|
||||||
if let Ok(v) = i64::from_str_radix(&String::from_utf8_lossy(token), 16) {
|
if let Ok(v) = i64::from_str_radix(&String::from_utf8_lossy(token), 16) {
|
||||||
|
|
|
@ -61,6 +61,62 @@ pub fn parse_int() {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn parse_binary_with_hex_format() {
|
||||||
|
let engine_state = EngineState::new();
|
||||||
|
let mut working_set = StateWorkingSet::new(&engine_state);
|
||||||
|
|
||||||
|
let (block, err) = parse(&mut working_set, None, b"0x[13]", true, &[]);
|
||||||
|
|
||||||
|
assert!(err.is_none());
|
||||||
|
assert!(block.len() == 1);
|
||||||
|
let expressions = &block[0];
|
||||||
|
assert!(expressions.len() == 1);
|
||||||
|
assert_eq!(expressions[0].expr, Expr::Binary(vec![0x13]))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn parse_binary_with_incomplete_hex_format() {
|
||||||
|
let engine_state = EngineState::new();
|
||||||
|
let mut working_set = StateWorkingSet::new(&engine_state);
|
||||||
|
|
||||||
|
let (block, err) = parse(&mut working_set, None, b"0x[3]", true, &[]);
|
||||||
|
|
||||||
|
assert!(err.is_none());
|
||||||
|
assert!(block.len() == 1);
|
||||||
|
let expressions = &block[0];
|
||||||
|
assert!(expressions.len() == 1);
|
||||||
|
assert_eq!(expressions[0].expr, Expr::Binary(vec![0x03]))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn parse_binary_with_binary_format() {
|
||||||
|
let engine_state = EngineState::new();
|
||||||
|
let mut working_set = StateWorkingSet::new(&engine_state);
|
||||||
|
|
||||||
|
let (block, err) = parse(&mut working_set, None, b"0b[1010 1000]", true, &[]);
|
||||||
|
|
||||||
|
assert!(err.is_none());
|
||||||
|
assert!(block.len() == 1);
|
||||||
|
let expressions = &block[0];
|
||||||
|
assert!(expressions.len() == 1);
|
||||||
|
assert_eq!(expressions[0].expr, Expr::Binary(vec![0b10101000]))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn parse_binary_with_incomplete_binary_format() {
|
||||||
|
let engine_state = EngineState::new();
|
||||||
|
let mut working_set = StateWorkingSet::new(&engine_state);
|
||||||
|
|
||||||
|
let (block, err) = parse(&mut working_set, None, b"0b[10]", true, &[]);
|
||||||
|
|
||||||
|
assert!(err.is_none());
|
||||||
|
assert!(block.len() == 1);
|
||||||
|
let expressions = &block[0];
|
||||||
|
assert!(expressions.len() == 1);
|
||||||
|
assert_eq!(expressions[0].expr, Expr::Binary(vec![0b00000010]))
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn parse_call() {
|
pub fn parse_call() {
|
||||||
let engine_state = EngineState::new();
|
let engine_state = EngineState::new();
|
||||||
|
|
Loading…
Reference in a new issue