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

View file

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