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:
merkrafter 2022-04-11 09:58:57 +02:00 committed by GitHub
parent 625e807a35
commit a30930324d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 99 additions and 21 deletions

View file

@ -1074,26 +1074,40 @@ pub fn parse_binary(
working_set: &mut StateWorkingSet,
span: Span,
) -> (Expression, Option<ParseError>) {
pub fn decode_hex(s: &str) -> Result<Vec<u8>, ParseIntError> {
(0..s.len())
.step_by(2)
.map(|i| u8::from_str_radix(&s[i..i + 2], 16))
.collect()
let (hex_value, err) = parse_binary_with_base(working_set, span, 16, 2, b"0x[", b"]");
if err.is_some() {
return parse_binary_with_base(working_set, span, 2, 8, b"0b[", b"]");
}
(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);
if let Some(token) = token.strip_prefix(b"0x[") {
if let Some(token) = token.strip_suffix(b"]") {
let (lexed, err) = lex(token, span.start + 3, &[b',', b'\r', b'\n'], &[], true);
if let Some(token) = token.strip_prefix(prefix) {
if let Some(token) = token.strip_suffix(suffix) {
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 {
match token.contents {
TokenContents::Item => {
let contents = working_set.get_span_contents(token.span);
hex_value.extend_from_slice(contents);
binary_value.extend_from_slice(contents);
}
TokenContents::Pipe => {
return (
@ -1105,20 +1119,21 @@ pub fn parse_binary(
}
}
if hex_value.len() % 2 != 0 {
return (
garbage(span),
Some(ParseError::IncorrectValue(
"incomplete binary".into(),
span,
"number of binary digits needs to be a multiple of 2".into(),
)),
);
let required_padding = (min_digits_per_byte - binary_value.len() % min_digits_per_byte)
% min_digits_per_byte;
if required_padding != 0 {
binary_value = {
let mut tail = binary_value;
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) => {
return (
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>) {
if let Some(token) = token.strip_prefix(b"0x") {
if let Ok(v) = i64::from_str_radix(&String::from_utf8_lossy(token), 16) {

View file

@ -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]
pub fn parse_call() {
let engine_state = EngineState::new();