forked from extern/nushell
Refactor to support multiple parse errors (#8765)
# Description This is a pretty heavy refactor of the parser to support multiple parser errors. It has a few issues we should address before landing: - [x] In some cases, error quality has gotten worse `1 / "bob"` for example - [x] if/else isn't currently parsing correctly - probably others # User-Facing Changes This may have error quality degradation as we adjust to the new error reporting mechanism. # Tests + Formatting Don't forget to add tests that cover your changes. Make sure you've run and fixed any issues with these commands: - `cargo fmt --all -- --check` to check standard code formatting (`cargo fmt --all` applies these changes) - `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A clippy::needless_collect` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass - `cargo run -- crates/nu-utils/standard_library/tests.nu` to run the tests for the standard library > **Note** > from `nushell` you can also use the `toolkit` as follows > ```bash > use toolkit.nu # or use an `env_change` hook to activate it automatically > toolkit check pr > ``` # After Submitting If your PR had any user-facing changes, update [the documentation](https://github.com/nushell/nushell.github.io) after the PR is merged, if necessary. This will help us keep the docs up to date.
This commit is contained in:
@ -50,7 +50,7 @@ pub fn test_dataframe(cmds: Vec<Box<dyn Command + 'static>>) {
|
||||
|
||||
let (block, delta) = {
|
||||
let mut working_set = StateWorkingSet::new(&engine_state);
|
||||
let (output, err) = parse(
|
||||
let output = parse(
|
||||
&mut working_set,
|
||||
None,
|
||||
example.example.as_bytes(),
|
||||
@ -58,7 +58,7 @@ pub fn test_dataframe(cmds: Vec<Box<dyn Command + 'static>>) {
|
||||
&[],
|
||||
);
|
||||
|
||||
if let Some(err) = err {
|
||||
if let Some(err) = working_set.parse_errors.first() {
|
||||
panic!("test parse error in `{}`: {:?}", example.example, err)
|
||||
}
|
||||
|
||||
|
@ -41,8 +41,10 @@ impl Command for Ast {
|
||||
let pipeline: Spanned<String> = call.req(engine_state, stack, 0)?;
|
||||
let mut working_set = StateWorkingSet::new(engine_state);
|
||||
|
||||
let (block_output, error_output) =
|
||||
parse(&mut working_set, None, pipeline.item.as_bytes(), false, &[]);
|
||||
let block_output = parse(&mut working_set, None, pipeline.item.as_bytes(), false, &[]);
|
||||
|
||||
let error_output = working_set.parse_errors.first();
|
||||
|
||||
let block_value = Value::String {
|
||||
val: format!("{block_output:#?}"),
|
||||
span: pipeline.span,
|
||||
|
@ -64,10 +64,9 @@ impl Command for FromNuon {
|
||||
let engine_state = engine_state.clone();
|
||||
|
||||
let mut working_set = StateWorkingSet::new(&engine_state);
|
||||
let mut error = None;
|
||||
let (mut block, err) =
|
||||
|
||||
let mut block =
|
||||
nu_parser::parse(&mut working_set, None, string_input.as_bytes(), false, &[]);
|
||||
error = error.or(err);
|
||||
|
||||
if let Some(pipeline) = block.pipelines.get(1) {
|
||||
if let Some(element) = pipeline.elements.get(0) {
|
||||
@ -146,7 +145,7 @@ impl Command for FromNuon {
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(err) = error {
|
||||
if let Some(err) = working_set.parse_errors.first() {
|
||||
return Err(ShellError::GenericError(
|
||||
"error when parsing nuon text".into(),
|
||||
"could not parse nuon text".into(),
|
||||
|
@ -166,10 +166,10 @@ pub fn eval_hook(
|
||||
vars.push((var_id, val));
|
||||
}
|
||||
|
||||
let (output, err) =
|
||||
let output =
|
||||
parse(&mut working_set, Some("hook"), val.as_bytes(), false, &[]);
|
||||
if let Some(err) = err {
|
||||
report_error(&working_set, &err);
|
||||
if let Some(err) = working_set.parse_errors.first() {
|
||||
report_error(&working_set, err);
|
||||
|
||||
return Err(ShellError::UnsupportedConfigValue(
|
||||
"valid source code".into(),
|
||||
|
@ -290,8 +290,8 @@ fn format_record(
|
||||
}
|
||||
}
|
||||
FormatOperation::ValueNeedEval(_col_name, span) => {
|
||||
let (exp, may_parse_err) = parse_expression(working_set, &[*span], &[], false);
|
||||
match may_parse_err {
|
||||
let exp = parse_expression(working_set, &[*span], &[], false);
|
||||
match working_set.parse_errors.first() {
|
||||
None => {
|
||||
let parsed_result = eval_expression(engine_state, stack, &exp);
|
||||
if let Ok(val) = parsed_result {
|
||||
|
@ -260,9 +260,14 @@ fn heuristic_parse_file(
|
||||
call: &Call,
|
||||
is_debug: bool,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let (filename, err) = unescape_unquote_string(path.as_bytes(), call.head);
|
||||
if err.is_none() {
|
||||
if let Ok(contents) = std::fs::read(&path) {
|
||||
let starting_error_count = working_set.parse_errors.len();
|
||||
let bytes = working_set.get_span_contents(call.head);
|
||||
let (filename, err) = unescape_unquote_string(bytes, call.head);
|
||||
if let Some(err) = err {
|
||||
working_set.error(err);
|
||||
}
|
||||
if starting_error_count == working_set.parse_errors.len() {
|
||||
if let Ok(contents) = std::fs::read(path) {
|
||||
match parse_script(
|
||||
working_set,
|
||||
Some(filename.as_str()),
|
||||
@ -314,13 +319,17 @@ fn parse_module(
|
||||
let end = working_set.next_span_start();
|
||||
|
||||
let new_span = Span::new(start, end);
|
||||
let (_, _, _, err) = parse_module_block(working_set, new_span, filename.as_bytes(), &[]);
|
||||
let starting_error_count = working_set.parse_errors.len();
|
||||
parse_module_block(working_set, new_span, filename.as_bytes(), &[]);
|
||||
|
||||
if err.is_some() {
|
||||
if starting_error_count != working_set.parse_errors.len() {
|
||||
if is_debug {
|
||||
let msg = format!(
|
||||
r#"Found : {}"#,
|
||||
err.expect("Unable to parse content as module")
|
||||
working_set
|
||||
.parse_errors
|
||||
.first()
|
||||
.expect("Unable to parse content as module")
|
||||
);
|
||||
Err(ShellError::GenericError(
|
||||
"Failed to parse content".to_string(),
|
||||
@ -344,9 +353,16 @@ fn parse_script(
|
||||
is_debug: bool,
|
||||
span: Span,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let (_, err) = parse(working_set, filename, contents, false, &[]);
|
||||
if err.is_some() {
|
||||
let msg = format!(r#"Found : {}"#, err.expect("Unable to parse content"));
|
||||
let starting_error_count = working_set.parse_errors.len();
|
||||
parse(working_set, filename, contents, false, &[]);
|
||||
if starting_error_count != working_set.parse_errors.len() {
|
||||
let msg = format!(
|
||||
r#"Found : {}"#,
|
||||
working_set
|
||||
.parse_errors
|
||||
.first()
|
||||
.expect("Unable to parse content")
|
||||
);
|
||||
if is_debug {
|
||||
Err(ShellError::GenericError(
|
||||
"Failed to parse content".to_string(),
|
||||
@ -369,9 +385,14 @@ fn parse_file_script(
|
||||
call: &Call,
|
||||
is_debug: bool,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let (filename, err) = unescape_unquote_string(path.as_bytes(), call.head);
|
||||
if err.is_none() {
|
||||
if let Ok(contents) = std::fs::read(&path) {
|
||||
let starting_error_count = working_set.parse_errors.len();
|
||||
let bytes = working_set.get_span_contents(call.head);
|
||||
let (filename, err) = unescape_unquote_string(bytes, call.head);
|
||||
if let Some(err) = err {
|
||||
working_set.error(err)
|
||||
}
|
||||
if starting_error_count == working_set.parse_errors.len() {
|
||||
if let Ok(contents) = std::fs::read(path) {
|
||||
parse_script(
|
||||
working_set,
|
||||
Some(filename.as_str()),
|
||||
@ -393,8 +414,13 @@ fn parse_file_module(
|
||||
call: &Call,
|
||||
is_debug: bool,
|
||||
) -> Result<PipelineData, ShellError> {
|
||||
let (filename, err) = unescape_unquote_string(path.as_bytes(), call.head);
|
||||
if err.is_none() {
|
||||
let starting_error_count = working_set.parse_errors.len();
|
||||
let bytes = working_set.get_span_contents(call.head);
|
||||
let (filename, err) = unescape_unquote_string(bytes, call.head);
|
||||
if let Some(err) = err {
|
||||
working_set.error(err);
|
||||
}
|
||||
if starting_error_count == working_set.parse_errors.len() {
|
||||
if let Ok(contents) = std::fs::read(path) {
|
||||
parse_module(working_set, Some(filename), &contents, is_debug, call.head)
|
||||
} else {
|
||||
|
Reference in New Issue
Block a user