Add binary literals (#4680)

This commit is contained in:
JT
2022-02-28 18:31:53 -05:00
committed by GitHub
parent e3100e6afd
commit a6a96b29cb
15 changed files with 199 additions and 10 deletions

View File

@ -7,6 +7,7 @@ pub enum FlatShape {
Garbage,
Nothing,
Bool,
Binary,
Int,
Float,
Range,
@ -35,6 +36,7 @@ impl Display for FlatShape {
match self {
FlatShape::Garbage => write!(f, "shape_garbage"),
FlatShape::Nothing => write!(f, "shape_nothing"),
FlatShape::Binary => write!(f, "shape_binary"),
FlatShape::Bool => write!(f, "shape_bool"),
FlatShape::Int => write!(f, "shape_int"),
FlatShape::Float => write!(f, "shape_float"),
@ -189,6 +191,9 @@ pub fn flatten_expression(
Expr::DateTime(_) => {
vec![(expr.span, FlatShape::DateTime)]
}
Expr::Binary(_) => {
vec![(expr.span, FlatShape::Binary)]
}
Expr::Int(_) => {
vec![(expr.span, FlatShape::Int)]
}

View File

@ -21,7 +21,10 @@ use crate::parse_keywords::{
};
use log::trace;
use std::collections::{HashMap, HashSet};
use std::{
collections::{HashMap, HashSet},
num::ParseIntError,
};
#[cfg(feature = "plugin")]
use crate::parse_keywords::parse_register;
@ -964,6 +967,85 @@ pub fn parse_call(
}
}
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 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);
let mut hex_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);
}
TokenContents::Pipe => {
return (
garbage(span),
Some(ParseError::Expected("binary".into(), span)),
);
}
TokenContents::Comment | TokenContents::Semicolon | TokenContents::Eol => {}
}
}
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 str = String::from_utf8_lossy(&hex_value).to_string();
match decode_hex(&str) {
Ok(v) => {
return (
Expression {
expr: Expr::Binary(v),
span,
ty: Type::Binary,
custom_completion: None,
},
err,
)
}
Err(x) => {
return (
garbage(span),
Some(ParseError::IncorrectValue(
"not a binary value".into(),
span,
x.to_string(),
)),
)
}
}
}
}
(
garbage(span),
Some(ParseError::Expected("binary".into(), span)),
)
}
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) {
@ -2132,6 +2214,7 @@ pub fn parse_shape_name(
) -> (SyntaxShape, Option<ParseError>) {
let result = match bytes {
b"any" => SyntaxShape::Any,
b"binary" => SyntaxShape::Binary,
b"block" => SyntaxShape::Block(None), //FIXME: Blocks should have known output types
b"cell-path" => SyntaxShape::CellPath,
b"duration" => SyntaxShape::Duration,
@ -3231,6 +3314,7 @@ pub fn parse_value(
SyntaxShape::Filepath => parse_filepath(working_set, span),
SyntaxShape::GlobPattern => parse_glob_pattern(working_set, span),
SyntaxShape::String => parse_string(working_set, span),
SyntaxShape::Binary => parse_binary(working_set, span),
SyntaxShape::Block(_) => {
if bytes.starts_with(b"{") {
trace!("parsing value as a block expression");
@ -3320,6 +3404,7 @@ pub fn parse_value(
parse_full_cell_path(working_set, None, span)
} else {
let shapes = [
SyntaxShape::Binary,
SyntaxShape::Int,
SyntaxShape::Number,
SyntaxShape::Range,
@ -4020,6 +4105,7 @@ pub fn discover_captures_in_expr(
}
}
}
Expr::Binary(_) => {}
Expr::Bool(_) => {}
Expr::Call(call) => {
let decl = working_set.get_decl(call.decl_id);