Speed up the parser and nuon parser a bit more (#4626)

This commit is contained in:
JT 2022-02-24 07:58:53 -05:00 committed by GitHub
parent c3979ef1cf
commit 308ab91aff
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 96 additions and 42 deletions

View file

@ -89,7 +89,7 @@ impl Command for FromNuon {
let (lite_block, err) = nu_parser::lite_parse(&lexed);
error = error.or(err);
let (block, err) = nu_parser::parse_block(&mut working_set, &lite_block, true);
let (mut block, err) = nu_parser::parse_block(&mut working_set, &lite_block, true);
error = error.or(err);
if let Some(pipeline) = block.pipelines.get(1) {
@ -119,7 +119,16 @@ impl Command for FromNuon {
}
}
let expr = if let Some(pipeline) = block.pipelines.get(0) {
let expr = if block.pipelines.is_empty() {
Expression {
expr: Expr::Nothing,
span: head,
custom_completion: None,
ty: Type::Nothing,
}
} else {
let mut pipeline = block.pipelines.remove(0);
if let Some(expr) = pipeline.expressions.get(1) {
return Err(ShellError::SpannedLabeledErrorRelated(
"error when loading nuon text".into(),
@ -134,22 +143,15 @@ impl Command for FromNuon {
));
}
if let Some(expr) = pipeline.expressions.get(0) {
expr.clone()
} else {
if pipeline.expressions.is_empty() {
Expression {
expr: Expr::Nothing,
span: head,
custom_completion: None,
ty: Type::Nothing,
}
}
} else {
Expression {
expr: Expr::Nothing,
span: head,
custom_completion: None,
ty: Type::Nothing,
} else {
pipeline.expressions.remove(0)
}
};

View file

@ -1091,12 +1091,23 @@ pub fn parse_range(
// looks like parent directory)
let contents = working_set.get_span_contents(span);
let token = if let Ok(s) = String::from_utf8(contents.into()) {
s
} else {
return (garbage(span), Some(ParseError::NonUtf8(span)));
};
if !token.contains("..") {
return (
garbage(span),
Some(ParseError::Expected(
"at least one range bound set".into(),
span,
)),
);
}
// First, figure out what exact operators are used and determine their positions
let dotdot_pos: Vec<_> = token.match_indices("..").map(|(pos, _)| pos).collect();
@ -1224,6 +1235,7 @@ pub(crate) fn parse_dollar_expr(
working_set: &mut StateWorkingSet,
span: Span,
) -> (Expression, Option<ParseError>) {
trace!("parsing: dollar expression");
let contents = working_set.get_span_contents(span);
if contents.starts_with(b"$\"") || contents.starts_with(b"$'") {
@ -1712,6 +1724,18 @@ pub fn parse_datetime(
trace!("parsing: datetime");
let bytes = working_set.get_span_contents(span);
if bytes.is_empty() || !bytes[0].is_ascii_digit() {
return (
garbage(span),
Some(ParseError::Mismatch(
"datetime".into(),
"non-datetime".into(),
span,
)),
);
}
let token = String::from_utf8_lossy(bytes).to_string();
if let Ok(datetime) = chrono::DateTime::parse_from_rfc3339(&token) {
@ -1727,8 +1751,8 @@ pub fn parse_datetime(
}
// Just the date
if let Ok(datetime) = chrono::DateTime::parse_from_rfc3339(&format!("{}T00:00:00+00:00", token))
{
let just_date = token.clone() + "T00:00:00+00:00";
if let Ok(datetime) = chrono::DateTime::parse_from_rfc3339(&just_date) {
return (
Expression {
expr: Expr::DateTime(datetime),
@ -1741,7 +1765,8 @@ pub fn parse_datetime(
}
// Date and time, assume UTC
if let Ok(datetime) = chrono::DateTime::parse_from_rfc3339(&format!("{}+00:00", token)) {
let datetime = token + "+00:00";
if let Ok(datetime) = chrono::DateTime::parse_from_rfc3339(&datetime) {
return (
Expression {
expr: Expr::DateTime(datetime),
@ -1779,6 +1804,18 @@ pub fn parse_duration(
}
let bytes = working_set.get_span_contents(span);
if bytes.is_empty() || (!bytes[0].is_ascii_digit() && bytes[0] != b'-') {
return (
garbage(span),
Some(ParseError::Mismatch(
"duration".into(),
"non-duration unit".into(),
span,
)),
);
}
let token = String::from_utf8_lossy(bytes).to_string();
let upper = token.to_uppercase();
@ -1874,6 +1911,18 @@ pub fn parse_filesize(
}
let bytes = working_set.get_span_contents(span);
if bytes.is_empty() || (!bytes[0].is_ascii_digit() && bytes[0] != b'-') {
return (
garbage(span),
Some(ParseError::Mismatch(
"filesize".into(),
"non-filesize unit".into(),
span,
)),
);
}
let token = String::from_utf8_lossy(bytes).to_string();
let upper = token.to_uppercase();
@ -3111,6 +3160,10 @@ pub fn parse_value(
) -> (Expression, Option<ParseError>) {
let bytes = working_set.get_span_contents(span);
if bytes.is_empty() {
return (garbage(span), Some(ParseError::IncompleteParser(span)));
}
// First, check the special-cases. These will likely represent specific values as expressions
// and may fit a variety of shapes.
//
@ -3121,37 +3174,35 @@ pub fn parse_value(
trace!("parsing: variable");
return parse_variable_expr(working_set, span);
} else if bytes.starts_with(b"$") {
trace!("parsing: dollar expression");
}
return parse_dollar_expr(working_set, span);
} else if bytes.starts_with(b"(") {
trace!("parsing: range or full path");
if let (expr, None) = parse_range(working_set, span) {
return (expr, None);
} else {
return parse_full_cell_path(working_set, None, span);
}
} else if bytes.starts_with(b"{") {
trace!("parsing: block or full path");
if !matches!(shape, SyntaxShape::Block(..)) {
if let (expr, None) = parse_full_cell_path(working_set, None, span) {
match bytes[0] {
b'$' => return parse_dollar_expr(working_set, span),
b'(' => {
if let (expr, None) = parse_range(working_set, span) {
return (expr, None);
} else {
return parse_full_cell_path(working_set, None, span);
}
}
if matches!(shape, SyntaxShape::Block(_)) || matches!(shape, SyntaxShape::Any) {
return parse_block_expression(working_set, shape, span);
} else if matches!(shape, SyntaxShape::Record) {
return parse_record(working_set, span);
} else {
return (
Expression::garbage(span),
Some(ParseError::Expected("non-block value".into(), span)),
);
b'{' => {
if !matches!(shape, SyntaxShape::Block(..)) {
if let (expr, None) = parse_full_cell_path(working_set, None, span) {
return (expr, None);
}
}
if matches!(shape, SyntaxShape::Block(_)) || matches!(shape, SyntaxShape::Any) {
return parse_block_expression(working_set, shape, span);
} else if matches!(shape, SyntaxShape::Record) {
return parse_record(working_set, span);
} else {
return (
Expression::garbage(span),
Some(ParseError::Expected("non-block value".into(), span)),
);
}
}
} else if bytes.starts_with(b"[") {
match shape {
b'[' => match shape {
SyntaxShape::Any
| SyntaxShape::List(_)
| SyntaxShape::Table
@ -3162,7 +3213,8 @@ pub fn parse_value(
Some(ParseError::Expected("non-[] value".into(), span)),
);
}
}
},
_ => {}
}
match shape {