From e4104d079203e5506f9d497366b3b9840f1b50c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20=C5=BD=C3=A1dn=C3=ADk?= Date: Wed, 5 Jun 2024 04:57:14 +0300 Subject: [PATCH] Span ID Refactor - Step 1 (#12960) # Description First part of SpanID refactoring series. This PR adds a `SpanId` type and a corresponding `span_id` field to `Expression`. Parser creating expressions will now add them to an array in `StateWorkingSet`, generates a corresponding ID and saves the ID to the Expression. The IDs are not used anywhere yet. For the rough overall plan, see https://github.com/nushell/nushell/issues/12963. # User-Facing Changes Hopefully none. This is only a refactor of Nushell's internals that shouldn't have visible side effects. # Tests + Formatting # After Submitting --- .../src/completions/custom_completions.rs | 22 +- crates/nu-command/src/system/run_external.rs | 7 +- crates/nu-engine/src/documentation.rs | 54 +- crates/nu-parser/src/known_external.rs | 56 +- crates/nu-parser/src/parse_keywords.rs | 802 ++++++++-------- crates/nu-parser/src/parser.rs | 891 ++++++++---------- crates/nu-parser/src/type_check.rs | 87 +- crates/nu-protocol/src/ast/call.rs | 23 +- crates/nu-protocol/src/ast/expression.rs | 54 +- crates/nu-protocol/src/engine/engine_state.rs | 30 +- crates/nu-protocol/src/engine/state_delta.rs | 4 +- .../src/engine/state_working_set.rs | 21 +- crates/nu-protocol/src/id.rs | 4 + crates/nuon/src/from.rs | 24 +- 14 files changed, 1029 insertions(+), 1050 deletions(-) diff --git a/crates/nu-cli/src/completions/custom_completions.rs b/crates/nu-cli/src/completions/custom_completions.rs index 17c8e6a924..f14971d466 100644 --- a/crates/nu-cli/src/completions/custom_completions.rs +++ b/crates/nu-cli/src/completions/custom_completions.rs @@ -52,18 +52,16 @@ impl Completer for CustomCompletion { decl_id: self.decl_id, head: span, arguments: vec![ - Argument::Positional(Expression { - span: Span::unknown(), - ty: Type::String, - expr: Expr::String(self.line.clone()), - custom_completion: None, - }), - Argument::Positional(Expression { - span: Span::unknown(), - ty: Type::Int, - expr: Expr::Int(line_pos as i64), - custom_completion: None, - }), + Argument::Positional(Expression::new_unknown( + Expr::String(self.line.clone()), + Span::unknown(), + Type::String, + )), + Argument::Positional(Expression::new_unknown( + Expr::Int(line_pos as i64), + Span::unknown(), + Type::Int, + )), ], parser_info: HashMap::new(), }, diff --git a/crates/nu-command/src/system/run_external.rs b/crates/nu-command/src/system/run_external.rs index d4645e87e8..614befe352 100644 --- a/crates/nu-command/src/system/run_external.rs +++ b/crates/nu-command/src/system/run_external.rs @@ -665,12 +665,7 @@ mod test { #[test] fn test_eval_argument() { fn expression(expr: Expr) -> Expression { - Expression { - expr, - span: Span::unknown(), - ty: Type::Any, - custom_completion: None, - } + Expression::new_unknown(expr, Span::unknown(), Type::Any) } fn eval(expr: Expr, spread: bool) -> Result, ShellError> { diff --git a/crates/nu-engine/src/documentation.rs b/crates/nu-engine/src/documentation.rs index 3cd1130060..94cef3298e 100644 --- a/crates/nu-engine/src/documentation.rs +++ b/crates/nu-engine/src/documentation.rs @@ -2,9 +2,9 @@ use crate::eval_call; use nu_protocol::{ ast::{Argument, Call, Expr, Expression, RecordItem}, debugger::WithoutDebug, - engine::{Command, EngineState, Stack}, - record, Category, Example, IntoPipelineData, PipelineData, Signature, Span, SyntaxShape, Type, - Value, + engine::{Command, EngineState, Stack, UNKNOWN_SPAN_ID}, + record, Category, Example, IntoPipelineData, PipelineData, Signature, Span, SpanId, + SyntaxShape, Type, Value, }; use std::{collections::HashMap, fmt::Write}; @@ -339,8 +339,9 @@ fn get_ansi_color_for_component_or_default( if let Some(color) = &engine_state.get_config().color_config.get(theme_component) { let caller_stack = &mut Stack::new().capture(); let span = Span::unknown(); + let span_id = UNKNOWN_SPAN_ID; - let argument_opt = get_argument_for_color_value(engine_state, color, span); + let argument_opt = get_argument_for_color_value(engine_state, color, span, span_id); // Call ansi command using argument if let Some(argument) = argument_opt { @@ -371,6 +372,7 @@ fn get_argument_for_color_value( engine_state: &EngineState, color: &&Value, span: Span, + span_id: SpanId, ) -> Option { match color { Value::Record { val, .. } => { @@ -378,43 +380,43 @@ fn get_argument_for_color_value( .iter() .map(|(k, v)| { RecordItem::Pair( - Expression { - expr: Expr::String(k.clone()), + Expression::new_existing( + Expr::String(k.clone()), span, - ty: Type::String, - custom_completion: None, - }, - Expression { - expr: Expr::String( + span_id, + Type::String, + ), + Expression::new_existing( + Expr::String( v.clone().to_expanded_string("", engine_state.get_config()), ), span, - ty: Type::String, - custom_completion: None, - }, + span_id, + Type::String, + ), ) }) .collect(); - Some(Argument::Positional(Expression { - span: Span::unknown(), - ty: Type::Record( + Some(Argument::Positional(Expression::new_existing( + Expr::Record(record_exp), + Span::unknown(), + UNKNOWN_SPAN_ID, + Type::Record( [ ("fg".to_string(), Type::String), ("attr".to_string(), Type::String), ] .into(), ), - expr: Expr::Record(record_exp), - custom_completion: None, - })) + ))) } - Value::String { val, .. } => Some(Argument::Positional(Expression { - span: Span::unknown(), - ty: Type::String, - expr: Expr::String(val.clone()), - custom_completion: None, - })), + Value::String { val, .. } => Some(Argument::Positional(Expression::new_existing( + Expr::String(val.clone()), + Span::unknown(), + UNKNOWN_SPAN_ID, + Type::String, + ))), _ => None, } } diff --git a/crates/nu-parser/src/known_external.rs b/crates/nu-parser/src/known_external.rs index 1463a3b080..453112aa32 100644 --- a/crates/nu-parser/src/known_external.rs +++ b/crates/nu-parser/src/known_external.rs @@ -1,7 +1,7 @@ use nu_engine::command_prelude::*; use nu_protocol::{ ast::{Argument, Expr, Expression}, - engine::CommandType, + engine::{CommandType, UNKNOWN_SPAN_ID}, }; #[derive(Clone)] @@ -56,43 +56,49 @@ impl Command for KnownExternal { }; let extern_name: Vec<_> = extern_name.split(' ').collect(); + let call_head_id = engine_state + .find_span_id(call.head) + .unwrap_or(UNKNOWN_SPAN_ID); - let arg_extern_name = Expression { - expr: Expr::String(extern_name[0].to_string()), - span: call.head, - ty: Type::String, - custom_completion: None, - }; + let arg_extern_name = Expression::new_existing( + Expr::String(extern_name[0].to_string()), + call.head, + call_head_id, + Type::String, + ); extern_call.add_positional(arg_extern_name); for subcommand in extern_name.into_iter().skip(1) { - extern_call.add_positional(Expression { - expr: Expr::String(subcommand.to_string()), - span: call.head, - ty: Type::String, - custom_completion: None, - }); + extern_call.add_positional(Expression::new_existing( + Expr::String(subcommand.to_string()), + call.head, + call_head_id, + Type::String, + )); } for arg in &call.arguments { match arg { Argument::Positional(positional) => extern_call.add_positional(positional.clone()), Argument::Named(named) => { + let named_span_id = engine_state + .find_span_id(named.0.span) + .unwrap_or(UNKNOWN_SPAN_ID); if let Some(short) = &named.1 { - extern_call.add_positional(Expression { - expr: Expr::String(format!("-{}", short.item)), - span: named.0.span, - ty: Type::String, - custom_completion: None, - }); + extern_call.add_positional(Expression::new_existing( + Expr::String(format!("-{}", short.item)), + named.0.span, + named_span_id, + Type::String, + )); } else { - extern_call.add_positional(Expression { - expr: Expr::String(format!("--{}", named.0.item)), - span: named.0.span, - ty: Type::String, - custom_completion: None, - }); + extern_call.add_positional(Expression::new_existing( + Expr::String(format!("--{}", named.0.item)), + named.0.span, + named_span_id, + Type::String, + )); } if let Some(arg) = &named.2 { extern_call.add_positional(arg.clone()); diff --git a/crates/nu-parser/src/parse_keywords.rs b/crates/nu-parser/src/parse_keywords.rs index 25a55c8489..2849b4e39c 100644 --- a/crates/nu-parser/src/parse_keywords.rs +++ b/crates/nu-parser/src/parse_keywords.rs @@ -113,12 +113,12 @@ pub fn parse_keyword(working_set: &mut StateWorkingSet, lite_command: &LiteComma // check help flag first. if call.named_iter().any(|(flag, _, _)| flag.item == "help") { let call_span = call.span(); - return Pipeline::from_vec(vec![Expression { - expr: Expr::Call(call), - span: call_span, - ty: Type::Any, - custom_completion: None, - }]); + return Pipeline::from_vec(vec![Expression::new( + working_set, + Expr::Call(call), + call_span, + Type::Any, + )]); } match cmd.name() { @@ -256,11 +256,11 @@ pub fn parse_for(working_set: &mut StateWorkingSet, lite_command: &LiteCommand) "internal error: Wrong call name for 'for' function".into(), Span::concat(spans), )); - return garbage(spans[0]); + return garbage(working_set, spans[0]); } if let Some(redirection) = lite_command.redirection.as_ref() { working_set.error(redirecting_builtin_error("for", redirection)); - return garbage(spans[0]); + return garbage(working_set, spans[0]); } // Parsing the spans and checking that they match the register signature @@ -272,7 +272,7 @@ pub fn parse_for(working_set: &mut StateWorkingSet, lite_command: &LiteCommand) "internal error: for declaration not found".into(), Span::concat(spans), )); - return garbage(spans[0]); + return garbage(working_set, spans[0]); } Some(decl_id) => { working_set.enter_scope(); @@ -289,16 +289,11 @@ pub fn parse_for(working_set: &mut StateWorkingSet, lite_command: &LiteCommand) check_call(working_set, call_span, &sig, &call); let Ok(is_help) = has_flag_const(working_set, &call, "help") else { - return garbage(spans[0]); + return garbage(working_set, spans[0]); }; if starting_error_count != working_set.parse_errors.len() || is_help { - return Expression { - expr: Expr::Call(call), - span: call_span, - ty: output, - custom_completion: None, - }; + return Expression::new(working_set, Expr::Call(call), call_span, output); } // Let's get our block and make sure it has the right signature @@ -355,12 +350,7 @@ pub fn parse_for(working_set: &mut StateWorkingSet, lite_command: &LiteCommand) ); } - Expression { - expr: Expr::Call(call), - span: call_span, - ty: Type::Nothing, - custom_completion: None, - } + Expression::new(working_set, Expr::Call(call), call_span, Type::Nothing) } /// If `name` is a keyword, emit an error. @@ -397,11 +387,11 @@ pub fn parse_def( "internal error: Wrong call name for def function".into(), Span::concat(spans), )); - return (garbage_pipeline(spans), None); + return (garbage_pipeline(working_set, spans), None); } if let Some(redirection) = lite_command.redirection.as_ref() { working_set.error(redirecting_builtin_error("def", redirection)); - return (garbage_pipeline(spans), None); + return (garbage_pipeline(working_set, spans), None); } // Parsing the spans and checking that they match the register signature @@ -413,7 +403,7 @@ pub fn parse_def( "internal error: def declaration not found".into(), Span::concat(spans), )); - return (garbage_pipeline(spans), None); + return (garbage_pipeline(working_set, spans), None); } Some(decl_id) => { working_set.enter_scope(); @@ -437,7 +427,7 @@ pub fn parse_def( String::from_utf8_lossy(&def_call).as_ref(), ) { working_set.error(err); - return (garbage_pipeline(spans), None); + return (garbage_pipeline(working_set, spans), None); } } @@ -481,17 +471,17 @@ pub fn parse_def( working_set.parse_errors.append(&mut new_errors); let Ok(is_help) = has_flag_const(working_set, &call, "help") else { - return (garbage_pipeline(spans), None); + return (garbage_pipeline(working_set, spans), None); }; if starting_error_count != working_set.parse_errors.len() || is_help { return ( - Pipeline::from_vec(vec![Expression { - expr: Expr::Call(call), - span: call_span, - ty: output, - custom_completion: None, - }]), + Pipeline::from_vec(vec![Expression::new( + working_set, + Expr::Call(call), + call_span, + output, + )]), None, ); } @@ -501,10 +491,10 @@ pub fn parse_def( }; let Ok(has_env) = has_flag_const(working_set, &call, "env") else { - return (garbage_pipeline(spans), None); + return (garbage_pipeline(working_set, spans), None); }; let Ok(has_wrapped) = has_flag_const(working_set, &call, "wrapped") else { - return (garbage_pipeline(spans), None); + return (garbage_pipeline(working_set, spans), None); }; // All positional arguments must be in the call positional vector by this point @@ -524,12 +514,12 @@ pub fn parse_def( name_expr_span, )); return ( - Pipeline::from_vec(vec![Expression { - expr: Expr::Call(call), - span: call_span, - ty: Type::Any, - custom_completion: None, - }]), + Pipeline::from_vec(vec![Expression::new( + working_set, + Expr::Call(call), + call_span, + Type::Any, + )]), None, ); } @@ -541,7 +531,7 @@ pub fn parse_def( "Could not get string from string expression".into(), name_expr.span, )); - return (garbage_pipeline(spans), None); + return (garbage_pipeline(working_set, spans), None); }; let mut result = None; @@ -574,12 +564,12 @@ pub fn parse_def( format!("...rest-like positional argument used in 'def --wrapped' supports only strings. Change the type annotation of ...{} to 'string'.", &rest.name))); return ( - Pipeline::from_vec(vec![Expression { - expr: Expr::Call(call), - span: call_span, - ty: Type::Any, - custom_completion: None, - }]), + Pipeline::from_vec(vec![Expression::new( + working_set, + Expr::Call(call), + call_span, + Type::Any, + )]), result, ); } @@ -588,12 +578,12 @@ pub fn parse_def( working_set.error(ParseError::MissingPositional("...rest-like positional argument".to_string(), name_expr.span, "def --wrapped must have a ...rest-like positional argument. Add '...rest: string' to the command's signature.".to_string())); return ( - Pipeline::from_vec(vec![Expression { - expr: Expr::Call(call), - span: call_span, - ty: Type::Any, - custom_completion: None, - }]), + Pipeline::from_vec(vec![Expression::new( + working_set, + Expr::Call(call), + call_span, + Type::Any, + )]), result, ); } @@ -644,12 +634,12 @@ pub fn parse_def( working_set.merge_predecl(name.as_bytes()); ( - Pipeline::from_vec(vec![Expression { - expr: Expr::Call(call), - span: call_span, - ty: Type::Any, - custom_completion: None, - }]), + Pipeline::from_vec(vec![Expression::new( + working_set, + Expr::Call(call), + call_span, + Type::Any, + )]), result, ) } @@ -679,11 +669,11 @@ pub fn parse_extern( "internal error: Wrong call name for extern command".into(), Span::concat(spans), )); - return garbage_pipeline(spans); + return garbage_pipeline(working_set, spans); } if let Some(redirection) = lite_command.redirection.as_ref() { working_set.error(redirecting_builtin_error("extern", redirection)); - return garbage_pipeline(spans); + return garbage_pipeline(working_set, spans); } // Parsing the spans and checking that they match the register signature @@ -695,7 +685,7 @@ pub fn parse_extern( "internal error: def declaration not found".into(), Span::concat(spans), )); - return garbage_pipeline(spans); + return garbage_pipeline(working_set, spans); } Some(decl_id) => { working_set.enter_scope(); @@ -709,7 +699,7 @@ pub fn parse_extern( String::from_utf8_lossy(&extern_call).as_ref(), ) { working_set.error(err); - return garbage_pipeline(spans); + return garbage_pipeline(working_set, spans); } } @@ -743,12 +733,12 @@ pub fn parse_extern( "main".to_string(), name_expr_span, )); - return Pipeline::from_vec(vec![Expression { - expr: Expr::Call(call), - span: call_span, - ty: Type::Any, - custom_completion: None, - }]); + return Pipeline::from_vec(vec![Expression::new( + working_set, + Expr::Call(call), + call_span, + Type::Any, + )]); } } @@ -809,12 +799,12 @@ pub fn parse_extern( } } - Pipeline::from_vec(vec![Expression { - expr: Expr::Call(call), - span: call_span, - ty: Type::Any, - custom_completion: None, - }]) + Pipeline::from_vec(vec![Expression::new( + working_set, + Expr::Call(call), + call_span, + Type::Any, + )]) } fn check_alias_name<'a>(working_set: &mut StateWorkingSet, spans: &'a [Span]) -> Option<&'a Span> { @@ -880,15 +870,15 @@ pub fn parse_alias( "Alias statement unparsable".into(), Span::concat(spans), )); - return garbage_pipeline(spans); + return garbage_pipeline(working_set, spans); } if let Some(redirection) = lite_command.redirection.as_ref() { working_set.error(redirecting_builtin_error("alias", redirection)); - return garbage_pipeline(spans); + return garbage_pipeline(working_set, spans); } if let Some(span) = check_alias_name(working_set, spans) { - return Pipeline::from_vec(vec![garbage(*span)]); + return Pipeline::from_vec(vec![garbage(working_set, *span)]); } if let Some(decl_id) = working_set.find_decl(b"alias") { @@ -912,15 +902,15 @@ pub fn parse_alias( .truncate(original_starting_error_count); let Ok(has_help_flag) = has_flag_const(working_set, &alias_call, "help") else { - return garbage_pipeline(spans); + return garbage_pipeline(working_set, spans); }; - let alias_pipeline = Pipeline::from_vec(vec![Expression { - expr: Expr::Call(alias_call.clone()), - span: Span::concat(spans), - ty: output, - custom_completion: None, - }]); + let alias_pipeline = Pipeline::from_vec(vec![Expression::new( + working_set, + Expr::Call(alias_call.clone()), + Span::concat(spans), + output, + )]); if has_help_flag { return alias_pipeline; @@ -931,7 +921,7 @@ pub fn parse_alias( "Missing positional after call check".to_string(), Span::concat(spans), )); - return garbage_pipeline(spans); + return garbage_pipeline(working_set, spans); }; let alias_name = if let Some(name) = alias_name_expr.as_string() { @@ -941,13 +931,13 @@ pub fn parse_alias( || name.parse::().is_ok() { working_set.error(ParseError::AliasNotValid(alias_name_expr.span)); - return garbage_pipeline(spans); + return garbage_pipeline(working_set, spans); } else { name } } else { working_set.error(ParseError::AliasNotValid(alias_name_expr.span)); - return garbage_pipeline(spans); + return garbage_pipeline(working_set, spans); }; if spans.len() >= split_id + 3 { @@ -1008,7 +998,7 @@ pub fn parse_alias( .truncate(original_starting_error_count); // ignore missing required positional } else { - return garbage_pipeline(replacement_spans); + return garbage_pipeline(working_set, replacement_spans); } } } @@ -1118,7 +1108,7 @@ pub fn parse_alias( Span::concat(spans), )); - garbage_pipeline(spans) + garbage_pipeline(working_set, spans) } // This one will trigger if `export` appears during eval, e.g., in a script @@ -1145,7 +1135,7 @@ pub fn parse_export_in_block( if let Some(redirection) = lite_command.redirection.as_ref() { working_set.error(redirecting_builtin_error(full_name, redirection)); - return garbage_pipeline(&lite_command.parts); + return garbage_pipeline(working_set, &lite_command.parts); } if let Some(decl_id) = working_set.find_decl(full_name.as_bytes()) { @@ -1170,23 +1160,23 @@ pub fn parse_export_in_block( check_call(working_set, call_span, &decl.signature(), &call); let Ok(is_help) = has_flag_const(working_set, &call, "help") else { - return garbage_pipeline(&lite_command.parts); + return garbage_pipeline(working_set, &lite_command.parts); }; if starting_error_count != working_set.parse_errors.len() || is_help { - return Pipeline::from_vec(vec![Expression { - expr: Expr::Call(call), - span: call_span, - ty: output, - custom_completion: None, - }]); + return Pipeline::from_vec(vec![Expression::new( + working_set, + Expr::Call(call), + call_span, + output, + )]); } } else { working_set.error(ParseError::UnknownState( format!("internal error: '{full_name}' declaration not found",), Span::concat(&lite_command.parts), )); - return garbage_pipeline(&lite_command.parts); + return garbage_pipeline(working_set, &lite_command.parts); }; if full_name == "export" { @@ -1195,7 +1185,7 @@ pub fn parse_export_in_block( "export".into(), lite_command.parts[0], )); - return garbage_pipeline(&lite_command.parts); + return garbage_pipeline(working_set, &lite_command.parts); } match full_name { @@ -1211,7 +1201,7 @@ pub fn parse_export_in_block( lite_command.parts[0], )); - garbage_pipeline(&lite_command.parts) + garbage_pipeline(working_set, &lite_command.parts) } } } @@ -1230,7 +1220,7 @@ pub fn parse_export_in_module( "expected export statement".into(), Span::concat(spans), )); - return (garbage_pipeline(spans), vec![]); + return (garbage_pipeline(working_set, spans), vec![]); } *sp @@ -1239,7 +1229,7 @@ pub fn parse_export_in_module( "got empty input for parsing export statement".into(), Span::concat(spans), )); - return (garbage_pipeline(spans), vec![]); + return (garbage_pipeline(working_set, spans), vec![]); }; let export_decl_id = if let Some(id) = working_set.find_decl(b"export") { @@ -1249,7 +1239,7 @@ pub fn parse_export_in_module( "missing export command".into(), export_span, )); - return (garbage_pipeline(spans), vec![]); + return (garbage_pipeline(working_set, spans), vec![]); }; let mut call = Box::new(Call { @@ -1288,7 +1278,7 @@ pub fn parse_export_in_module( "missing 'export def' command".into(), export_span, )); - return (garbage_pipeline(spans), vec![]); + return (garbage_pipeline(working_set, spans), vec![]); }; // Trying to warp the 'def' call into the 'export def' in a very clumsy way @@ -1324,7 +1314,7 @@ pub fn parse_export_in_module( "missing 'export extern' command".into(), export_span, )); - return (garbage_pipeline(spans), vec![]); + return (garbage_pipeline(working_set, spans), vec![]); }; // Trying to warp the 'def' call into the 'export def' in a very clumsy way @@ -1379,7 +1369,7 @@ pub fn parse_export_in_module( "missing 'export alias' command".into(), export_span, )); - return (garbage_pipeline(spans), vec![]); + return (garbage_pipeline(working_set, spans), vec![]); }; // Trying to warp the 'alias' call into the 'export alias' in a very clumsy way @@ -1435,7 +1425,7 @@ pub fn parse_export_in_module( "missing 'export use' command".into(), export_span, )); - return (garbage_pipeline(spans), vec![]); + return (garbage_pipeline(working_set, spans), vec![]); }; // Trying to warp the 'use' call into the 'export use' in a very clumsy way @@ -1466,7 +1456,7 @@ pub fn parse_export_in_module( "missing 'export module' command".into(), export_span, )); - return (garbage_pipeline(spans), vec![]); + return (garbage_pipeline(working_set, spans), vec![]); }; // Trying to warp the 'module' call into the 'export module' in a very clumsy way @@ -1518,7 +1508,7 @@ pub fn parse_export_in_module( "missing 'export const' command".into(), export_span, )); - return (garbage_pipeline(spans), vec![]); + return (garbage_pipeline(working_set, spans), vec![]); }; // Trying to warp the 'const' call into the 'export const' in a very clumsy way @@ -1580,12 +1570,12 @@ pub fn parse_export_in_module( }; ( - Pipeline::from_vec(vec![Expression { - expr: Expr::Call(call), - span: Span::concat(spans), - ty: Type::Any, - custom_completion: None, - }]), + Pipeline::from_vec(vec![Expression::new( + working_set, + Expr::Call(call), + Span::concat(spans), + Type::Any, + )]), exportables, ) } @@ -1599,7 +1589,7 @@ pub fn parse_export_env( "internal error: Wrong call name for 'export-env' command".into(), Span::concat(spans), )); - return (garbage_pipeline(spans), None); + return (garbage_pipeline(working_set, spans), None); } if spans.len() < 2 { @@ -1608,7 +1598,7 @@ pub fn parse_export_env( Span::concat(spans), "export-env ".into(), )); - return (garbage_pipeline(spans), None); + return (garbage_pipeline(working_set, spans), None); } let call = match working_set.find_decl(b"export-env") { @@ -1623,17 +1613,17 @@ pub fn parse_export_env( check_call(working_set, call_span, &decl.signature(), &call); let Ok(is_help) = has_flag_const(working_set, &call, "help") else { - return (garbage_pipeline(spans), None); + return (garbage_pipeline(working_set, spans), None); }; if starting_error_count != working_set.parse_errors.len() || is_help { return ( - Pipeline::from_vec(vec![Expression { - expr: Expr::Call(call), - span: call_span, - ty: output, - custom_completion: None, - }]), + Pipeline::from_vec(vec![Expression::new( + working_set, + Expr::Call(call), + call_span, + output, + )]), None, ); } @@ -1645,7 +1635,7 @@ pub fn parse_export_env( "internal error: 'export-env' declaration not found".into(), Span::concat(spans), )); - return (garbage_pipeline(spans), None); + return (garbage_pipeline(working_set, spans), None); } }; @@ -1657,22 +1647,22 @@ pub fn parse_export_env( "internal error: 'export-env' block is not a block".into(), block.span, )); - return (garbage_pipeline(spans), None); + return (garbage_pipeline(working_set, spans), None); } } else { working_set.error(ParseError::UnknownState( "internal error: 'export-env' block is missing".into(), Span::concat(spans), )); - return (garbage_pipeline(spans), None); + return (garbage_pipeline(working_set, spans), None); }; - let pipeline = Pipeline::from_vec(vec![Expression { - expr: Expr::Call(call), - span: Span::concat(spans), - ty: Type::Any, - custom_completion: None, - }]); + let pipeline = Pipeline::from_vec(vec![Expression::new( + working_set, + Expr::Call(call), + Span::concat(spans), + Type::Any, + )]); (pipeline, Some(block_id)) } @@ -1878,12 +1868,14 @@ pub fn parse_module_block( command.parts[0], )); - block.pipelines.push(garbage_pipeline(&command.parts)) + block + .pipelines + .push(garbage_pipeline(working_set, &command.parts)) } } } else { working_set.error(ParseError::Expected("not a pipeline", span)); - block.pipelines.push(garbage_pipeline(&[span])) + block.pipelines.push(garbage_pipeline(working_set, &[span])) } } @@ -2050,7 +2042,7 @@ pub fn parse_module( if let Some(redirection) = lite_command.redirection.as_ref() { working_set.error(redirecting_builtin_error("module", redirection)); - return (garbage_pipeline(spans), None); + return (garbage_pipeline(working_set, spans), None); } let mut module_comments = lite_command.comments.clone(); @@ -2079,17 +2071,17 @@ pub fn parse_module( check_call(working_set, call_span, &decl.signature(), &call); let Ok(is_help) = has_flag_const(working_set, &call, "help") else { - return (garbage_pipeline(spans), None); + return (garbage_pipeline(working_set, spans), None); }; if starting_error_count != working_set.parse_errors.len() || is_help { return ( - Pipeline::from_vec(vec![Expression { - expr: Expr::Call(call), - span: call_span, - ty: output, - custom_completion: None, - }]), + Pipeline::from_vec(vec![Expression::new( + working_set, + Expr::Call(call), + call_span, + output, + )]), None, ); } @@ -2101,7 +2093,7 @@ pub fn parse_module( "internal error: 'module' or 'export module' declaration not found".into(), Span::concat(spans), )); - return (garbage_pipeline(spans), None); + return (garbage_pipeline(working_set, spans), None); } }; @@ -2117,12 +2109,12 @@ pub fn parse_module( name.span, )); return ( - Pipeline::from_vec(vec![Expression { - expr: Expr::Call(call), - span: call_span, - ty: Type::Any, - custom_completion: None, - }]), + Pipeline::from_vec(vec![Expression::new( + working_set, + Expr::Call(call), + call_span, + Type::Any, + )]), None, ); } @@ -2133,22 +2125,22 @@ pub fn parse_module( "internal error: name not a string".into(), Span::concat(spans), )); - return (garbage_pipeline(spans), None); + return (garbage_pipeline(working_set, spans), None); } } else { working_set.error(ParseError::UnknownState( "internal error: missing positional".into(), Span::concat(spans), )); - return (garbage_pipeline(spans), None); + return (garbage_pipeline(working_set, spans), None); }; - let pipeline = Pipeline::from_vec(vec![Expression { - expr: Expr::Call(call), - span: call_span, - ty: Type::Any, - custom_completion: None, - }]); + let pipeline = Pipeline::from_vec(vec![Expression::new( + working_set, + Expr::Call(call), + call_span, + Type::Any, + )]); if spans.len() == split_id + 1 { if let Some(module_id) = parse_module_file_or_dir( @@ -2173,7 +2165,7 @@ pub fn parse_module( Span::concat(spans), )); - return (garbage_pipeline(spans), None); + return (garbage_pipeline(working_set, spans), None); } let module_name = module_name_or_path; @@ -2187,7 +2179,7 @@ pub fn parse_module( start += 1; } else { working_set.error(ParseError::Expected("block", block_span)); - return (garbage_pipeline(spans), None); + return (garbage_pipeline(working_set, spans), None); } if block_bytes.ends_with(b"}") { @@ -2206,12 +2198,7 @@ pub fn parse_module( module_comments.extend(inner_comments); let module_id = working_set.add_module(&module_name, module, module_comments); - let block_expr = Expression { - expr: Expr::Block(block_id), - span: block_span, - ty: Type::Block, - custom_completion: None, - }; + let block_expr = Expression::new(working_set, Expr::Block(block_id), block_span, Type::Block); let module_decl_id = working_set .find_decl(b"module") @@ -2228,12 +2215,12 @@ pub fn parse_module( }); ( - Pipeline::from_vec(vec![Expression { - expr: Expr::Call(call), - span: Span::concat(spans), - ty: Type::Any, - custom_completion: None, - }]), + Pipeline::from_vec(vec![Expression::new( + working_set, + Expr::Call(call), + Span::concat(spans), + Type::Any, + )]), Some(module_id), ) } @@ -2257,7 +2244,7 @@ pub fn parse_use( "internal error: Wrong call name for 'use' command".into(), Span::concat(spans), )); - return (garbage_pipeline(spans), vec![]); + return (garbage_pipeline(working_set, spans), vec![]); } if working_set.get_span_contents(name_span) != b"use" { @@ -2265,12 +2252,12 @@ pub fn parse_use( "internal error: Wrong call name for 'use' command".into(), Span::concat(spans), )); - return (garbage_pipeline(spans), vec![]); + return (garbage_pipeline(working_set, spans), vec![]); } if let Some(redirection) = lite_command.redirection.as_ref() { working_set.error(redirecting_builtin_error("use", redirection)); - return (garbage_pipeline(spans), vec![]); + return (garbage_pipeline(working_set, spans), vec![]); } let (call, call_span, args_spans) = match working_set.find_decl(b"use") { @@ -2291,17 +2278,17 @@ pub fn parse_use( check_call(working_set, call_span, &decl.signature(), &call); let Ok(is_help) = has_flag_const(working_set, &call, "help") else { - return (garbage_pipeline(spans), vec![]); + return (garbage_pipeline(working_set, spans), vec![]); }; if starting_error_count != working_set.parse_errors.len() || is_help { return ( - Pipeline::from_vec(vec![Expression { - expr: Expr::Call(call), - span: call_span, - ty: output, - custom_completion: None, - }]), + Pipeline::from_vec(vec![Expression::new( + working_set, + Expr::Call(call), + call_span, + output, + )]), vec![], ); } @@ -2313,7 +2300,7 @@ pub fn parse_use( "internal error: 'use' declaration not found".into(), Span::concat(spans), )); - return (garbage_pipeline(spans), vec![]); + return (garbage_pipeline(working_set, spans), vec![]); } }; @@ -2330,7 +2317,7 @@ pub fn parse_use( "internal error: Import pattern positional is not import pattern".into(), import_pattern_expr.span, )); - return (garbage_pipeline(spans), vec![]); + return (garbage_pipeline(working_set, spans), vec![]); }; let (mut import_pattern, module, module_id) = if let Some(module_id) = import_pattern.head.id { @@ -2376,12 +2363,12 @@ pub fn parse_use( String::from_utf8_lossy(&import_pattern.head.name).to_string(), )); return ( - Pipeline::from_vec(vec![Expression { - expr: Expr::Call(call), - span: call_span, - ty: Type::Any, - custom_completion: None, - }]), + Pipeline::from_vec(vec![Expression::new( + working_set, + Expr::Call(call), + call_span, + Type::Any, + )]), vec![], ); }; @@ -2439,23 +2426,23 @@ pub fn parse_use( working_set.use_variables(constants); // Create a new Use command call to pass the import pattern as parser info - let import_pattern_expr = Expression { - expr: Expr::ImportPattern(Box::new(import_pattern)), - span: Span::concat(args_spans), - ty: Type::Any, - custom_completion: None, - }; + let import_pattern_expr = Expression::new( + working_set, + Expr::ImportPattern(Box::new(import_pattern)), + Span::concat(args_spans), + Type::Any, + ); let mut call = call; call.set_parser_info("import_pattern".to_string(), import_pattern_expr); ( - Pipeline::from_vec(vec![Expression { - expr: Expr::Call(call), - span: Span::concat(spans), - ty: Type::Any, - custom_completion: None, - }]), + Pipeline::from_vec(vec![Expression::new( + working_set, + Expr::Call(call), + Span::concat(spans), + Type::Any, + )]), exportables, ) } @@ -2468,11 +2455,11 @@ pub fn parse_hide(working_set: &mut StateWorkingSet, lite_command: &LiteCommand) "internal error: Wrong call name for 'hide' command".into(), Span::concat(spans), )); - return garbage_pipeline(spans); + return garbage_pipeline(working_set, spans); } if let Some(redirection) = lite_command.redirection.as_ref() { working_set.error(redirecting_builtin_error("hide", redirection)); - return garbage_pipeline(spans); + return garbage_pipeline(working_set, spans); } let (call, args_spans) = match working_set.find_decl(b"hide") { @@ -2487,16 +2474,16 @@ pub fn parse_hide(working_set: &mut StateWorkingSet, lite_command: &LiteCommand) check_call(working_set, call_span, &decl.signature(), &call); let Ok(is_help) = has_flag_const(working_set, &call, "help") else { - return garbage_pipeline(spans); + return garbage_pipeline(working_set, spans); }; if starting_error_count != working_set.parse_errors.len() || is_help { - return Pipeline::from_vec(vec![Expression { - expr: Expr::Call(call), - span: call_span, - ty: output, - custom_completion: None, - }]); + return Pipeline::from_vec(vec![Expression::new( + working_set, + Expr::Call(call), + call_span, + output, + )]); } (call, &spans[1..]) @@ -2506,7 +2493,7 @@ pub fn parse_hide(working_set: &mut StateWorkingSet, lite_command: &LiteCommand) "internal error: 'hide' declaration not found".into(), Span::concat(spans), )); - return garbage_pipeline(spans); + return garbage_pipeline(working_set, spans); } }; @@ -2523,7 +2510,7 @@ pub fn parse_hide(working_set: &mut StateWorkingSet, lite_command: &LiteCommand) "internal error: Import pattern positional is not import pattern".into(), import_pattern_expr.span, )); - return garbage_pipeline(spans); + return garbage_pipeline(working_set, spans); }; let bytes = working_set.get_span_contents(spans[0]); @@ -2554,7 +2541,7 @@ pub fn parse_hide(working_set: &mut StateWorkingSet, lite_command: &LiteCommand) spans[1], String::from_utf8_lossy(&import_pattern.head.name).to_string(), )); - return garbage_pipeline(spans); + return garbage_pipeline(working_set, spans); }; // This kind of inverts the import pattern matching found in parse_use() @@ -2623,28 +2610,28 @@ pub fn parse_hide(working_set: &mut StateWorkingSet, lite_command: &LiteCommand) working_set.hide_decls(&decls_to_hide); // Create a new Use command call to pass the new import pattern - let import_pattern_expr = Expression { - expr: Expr::ImportPattern(Box::new(import_pattern)), - span: Span::concat(args_spans), - ty: Type::Any, - custom_completion: None, - }; + let import_pattern_expr = Expression::new( + working_set, + Expr::ImportPattern(Box::new(import_pattern)), + Span::concat(args_spans), + Type::Any, + ); let mut call = call; call.set_parser_info("import_pattern".to_string(), import_pattern_expr); - Pipeline::from_vec(vec![Expression { - expr: Expr::Call(call), - span: Span::concat(spans), - ty: Type::Any, - custom_completion: None, - }]) + Pipeline::from_vec(vec![Expression::new( + working_set, + Expr::Call(call), + Span::concat(spans), + Type::Any, + )]) } else { working_set.error(ParseError::UnknownState( "Expected structure: hide ".into(), Span::concat(spans), )); - garbage_pipeline(spans) + garbage_pipeline(working_set, spans) } } @@ -2657,12 +2644,12 @@ pub fn parse_overlay_new(working_set: &mut StateWorkingSet, call: Box) -> Ok(s) => (s, expr.span), Err(err) => { working_set.error(err.wrap(working_set, call_span)); - return garbage_pipeline(&[call_span]); + return garbage_pipeline(working_set, &[call_span]); } }, Err(err) => { working_set.error(err.wrap(working_set, call_span)); - return garbage_pipeline(&[call_span]); + return garbage_pipeline(working_set, &[call_span]); } } } else { @@ -2670,15 +2657,15 @@ pub fn parse_overlay_new(working_set: &mut StateWorkingSet, call: Box) -> "internal error: Missing required positional after call parsing".into(), call_span, )); - return garbage_pipeline(&[call_span]); + return garbage_pipeline(working_set, &[call_span]); }; - let pipeline = Pipeline::from_vec(vec![Expression { - expr: Expr::Call(call), - span: call_span, - ty: Type::Any, - custom_completion: None, - }]); + let pipeline = Pipeline::from_vec(vec![Expression::new( + working_set, + Expr::Call(call), + call_span, + Type::Any, + )]); let module_id = working_set.add_module( &overlay_name, @@ -2706,12 +2693,12 @@ pub fn parse_overlay_use(working_set: &mut StateWorkingSet, call: Box) -> Ok(s) => (s, expr.span), Err(err) => { working_set.error(err.wrap(working_set, call_span)); - return garbage_pipeline(&[call_span]); + return garbage_pipeline(working_set, &[call_span]); } }, Err(err) => { working_set.error(err.wrap(working_set, call_span)); - return garbage_pipeline(&[call_span]); + return garbage_pipeline(working_set, &[call_span]); } } } else { @@ -2719,7 +2706,7 @@ pub fn parse_overlay_use(working_set: &mut StateWorkingSet, call: Box) -> "internal error: Missing required positional after call parsing".into(), call_span, )); - return garbage_pipeline(&[call_span]); + return garbage_pipeline(working_set, &[call_span]); }; let new_name = if let Some(kw_expression) = call.positional_nth(1) { @@ -2732,12 +2719,12 @@ pub fn parse_overlay_use(working_set: &mut StateWorkingSet, call: Box) -> }), Err(err) => { working_set.error(err.wrap(working_set, call_span)); - return garbage_pipeline(&[call_span]); + return garbage_pipeline(working_set, &[call_span]); } }, Err(err) => { working_set.error(err.wrap(working_set, call_span)); - return garbage_pipeline(&[call_span]); + return garbage_pipeline(working_set, &[call_span]); } } } else { @@ -2745,25 +2732,25 @@ pub fn parse_overlay_use(working_set: &mut StateWorkingSet, call: Box) -> "as keyword".to_string(), kw_expression.span, )); - return garbage_pipeline(&[call_span]); + return garbage_pipeline(working_set, &[call_span]); } } else { None }; let Ok(has_prefix) = has_flag_const(working_set, &call, "prefix") else { - return garbage_pipeline(&[call_span]); + return garbage_pipeline(working_set, &[call_span]); }; let Ok(do_reload) = has_flag_const(working_set, &call, "reload") else { - return garbage_pipeline(&[call_span]); + return garbage_pipeline(working_set, &[call_span]); }; - let pipeline = Pipeline::from_vec(vec![Expression { - expr: Expr::Call(call.clone()), - span: call_span, - ty: Type::Any, - custom_completion: None, - }]); + let pipeline = Pipeline::from_vec(vec![Expression::new( + working_set, + Expr::Call(call.clone()), + call_span, + Type::Any, + )]); let (final_overlay_name, origin_module, origin_module_id, is_module_updated) = if let Some(overlay_frame) = working_set.find_overlay(overlay_name.as_bytes()) { @@ -2898,24 +2885,24 @@ pub fn parse_overlay_use(working_set: &mut StateWorkingSet, call: Box) -> let mut call = call; call.set_parser_info( "overlay_expr".to_string(), - Expression { - expr: Expr::Overlay(if is_module_updated { + Expression::new( + working_set, + Expr::Overlay(if is_module_updated { Some(origin_module_id) } else { None }), - span: overlay_name_span, - ty: Type::Any, - custom_completion: None, - }, + overlay_name_span, + Type::Any, + ), ); - Pipeline::from_vec(vec![Expression { - expr: Expr::Call(call), - span: call_span, - ty: Type::Any, - custom_completion: None, - }]) + Pipeline::from_vec(vec![Expression::new( + working_set, + Expr::Call(call), + call_span, + Type::Any, + )]) } pub fn parse_overlay_hide(working_set: &mut StateWorkingSet, call: Box) -> Pipeline { @@ -2927,12 +2914,12 @@ pub fn parse_overlay_hide(working_set: &mut StateWorkingSet, call: Box) -> Ok(s) => (s, expr.span), Err(err) => { working_set.error(err.wrap(working_set, call_span)); - return garbage_pipeline(&[call_span]); + return garbage_pipeline(working_set, &[call_span]); } }, Err(err) => { working_set.error(err.wrap(working_set, call_span)); - return garbage_pipeline(&[call_span]); + return garbage_pipeline(working_set, &[call_span]); } } } else { @@ -2943,15 +2930,15 @@ pub fn parse_overlay_hide(working_set: &mut StateWorkingSet, call: Box) -> }; let Ok(keep_custom) = has_flag_const(working_set, &call, "keep-custom") else { - return garbage_pipeline(&[call_span]); + return garbage_pipeline(working_set, &[call_span]); }; - let pipeline = Pipeline::from_vec(vec![Expression { - expr: Expr::Call(call), - span: call_span, - ty: Type::Any, - custom_completion: None, - }]); + let pipeline = Pipeline::from_vec(vec![Expression::new( + working_set, + Expr::Call(call), + call_span, + Type::Any, + )]); if overlay_name == DEFAULT_OVERLAY_NAME { working_set.error(ParseError::CantHideDefaultOverlay( @@ -3016,12 +3003,12 @@ pub fn parse_let(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipeline let block_id = working_set.add_block(Arc::new(rvalue_block)); - let rvalue = Expression { - expr: Expr::Block(block_id), - span: rvalue_span, - ty: output_type, - custom_completion: None, - }; + let rvalue = Expression::new( + working_set, + Expr::Block(block_id), + rvalue_span, + output_type, + ); let mut idx = 0; let (lvalue, explicit_type) = @@ -3066,24 +3053,24 @@ pub fn parse_let(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipeline parser_info: HashMap::new(), }); - return Pipeline::from_vec(vec![Expression { - expr: Expr::Call(call), - span: Span::concat(spans), - ty: Type::Any, - custom_completion: None, - }]); + return Pipeline::from_vec(vec![Expression::new( + working_set, + Expr::Call(call), + Span::concat(spans), + Type::Any, + )]); } } } let ParsedInternalCall { call, output } = parse_internal_call(working_set, spans[0], &spans[1..], decl_id); - return Pipeline::from_vec(vec![Expression { - expr: Expr::Call(call), - span: Span::concat(spans), - ty: output, - custom_completion: None, - }]); + return Pipeline::from_vec(vec![Expression::new( + working_set, + Expr::Call(call), + Span::concat(spans), + output, + )]); } else { working_set.error(ParseError::UnknownState( "internal error: let or const statements not found in core language".into(), @@ -3096,7 +3083,7 @@ pub fn parse_let(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipeline Span::concat(spans), )); - garbage_pipeline(spans) + garbage_pipeline(working_set, spans) } pub fn parse_const(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipeline { @@ -3104,7 +3091,7 @@ pub fn parse_const(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipelin // JT: Disabling check_name because it doesn't work with optional types in the declaration // if let Some(span) = check_name(working_set, spans) { - // return Pipeline::from_vec(vec![garbage(*span)]); + // return Pipeline::from_vec(vec![garbage(working_set, *span)]); // } if let Some(decl_id) = working_set.find_decl(b"const") { @@ -3212,24 +3199,24 @@ pub fn parse_const(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipelin parser_info: HashMap::new(), }); - return Pipeline::from_vec(vec![Expression { - expr: Expr::Call(call), - span: Span::concat(spans), - ty: Type::Any, - custom_completion: None, - }]); + return Pipeline::from_vec(vec![Expression::new( + working_set, + Expr::Call(call), + Span::concat(spans), + Type::Any, + )]); } } } let ParsedInternalCall { call, output } = parse_internal_call(working_set, spans[0], &spans[1..], decl_id); - return Pipeline::from_vec(vec![Expression { - expr: Expr::Call(call), - span: Span::concat(spans), - ty: output, - custom_completion: None, - }]); + return Pipeline::from_vec(vec![Expression::new( + working_set, + Expr::Call(call), + Span::concat(spans), + output, + )]); } else { working_set.error(ParseError::UnknownState( "internal error: let or const statements not found in core language".into(), @@ -3242,7 +3229,7 @@ pub fn parse_const(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipelin Span::concat(spans), )); - garbage_pipeline(spans) + garbage_pipeline(working_set, spans) } pub fn parse_mut(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipeline { @@ -3250,7 +3237,7 @@ pub fn parse_mut(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipeline // JT: Disabling check_name because it doesn't work with optional types in the declaration // if let Some(span) = check_name(working_set, spans) { - // return Pipeline::from_vec(vec![garbage(*span)]); + // return Pipeline::from_vec(vec![garbage(working_set, *span)]); // } if let Some(decl_id) = working_set.find_decl(b"mut") { @@ -3280,12 +3267,12 @@ pub fn parse_mut(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipeline let block_id = working_set.add_block(Arc::new(rvalue_block)); - let rvalue = Expression { - expr: Expr::Block(block_id), - span: rvalue_span, - ty: output_type, - custom_completion: None, - }; + let rvalue = Expression::new( + working_set, + Expr::Block(block_id), + rvalue_span, + output_type, + ); let mut idx = 0; @@ -3331,24 +3318,24 @@ pub fn parse_mut(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipeline parser_info: HashMap::new(), }); - return Pipeline::from_vec(vec![Expression { - expr: Expr::Call(call), - span: Span::concat(spans), - ty: Type::Any, - custom_completion: None, - }]); + return Pipeline::from_vec(vec![Expression::new( + working_set, + Expr::Call(call), + Span::concat(spans), + Type::Any, + )]); } } } let ParsedInternalCall { call, output } = parse_internal_call(working_set, spans[0], &spans[1..], decl_id); - return Pipeline::from_vec(vec![Expression { - expr: Expr::Call(call), - span: Span::concat(spans), - ty: output, - custom_completion: None, - }]); + return Pipeline::from_vec(vec![Expression::new( + working_set, + Expr::Call(call), + Span::concat(spans), + output, + )]); } else { working_set.error(ParseError::UnknownState( "internal error: let or const statements not found in core language".into(), @@ -3361,7 +3348,7 @@ pub fn parse_mut(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipeline Span::concat(spans), )); - garbage_pipeline(spans) + garbage_pipeline(working_set, spans) } pub fn parse_source(working_set: &mut StateWorkingSet, lite_command: &LiteCommand) -> Pipeline { @@ -3377,7 +3364,7 @@ pub fn parse_source(working_set: &mut StateWorkingSet, lite_command: &LiteComman "source-env" }; working_set.error(redirecting_builtin_error(name, redirection)); - return garbage_pipeline(spans); + return garbage_pipeline(working_set, spans); } let scoped = name == b"source-env"; @@ -3392,16 +3379,16 @@ pub fn parse_source(working_set: &mut StateWorkingSet, lite_command: &LiteComman parse_internal_call(working_set, spans[0], &spans[1..], decl_id); let Ok(is_help) = has_flag_const(working_set, &call, "help") else { - return garbage_pipeline(spans); + return garbage_pipeline(working_set, spans); }; if is_help { - return Pipeline::from_vec(vec![Expression { - expr: Expr::Call(call), - span: Span::concat(spans), - ty: output, - custom_completion: None, - }]); + return Pipeline::from_vec(vec![Expression::new( + working_set, + Expr::Call(call), + Span::concat(spans), + output, + )]); } // Command and one file name @@ -3412,12 +3399,12 @@ pub fn parse_source(working_set: &mut StateWorkingSet, lite_command: &LiteComman Ok(val) => val, Err(err) => { working_set.error(err.wrap(working_set, Span::concat(&spans[1..]))); - return Pipeline::from_vec(vec![Expression { - expr: Expr::Call(call), - span: Span::concat(&spans[1..]), - ty: Type::Any, - custom_completion: None, - }]); + return Pipeline::from_vec(vec![Expression::new( + working_set, + Expr::Call(call), + Span::concat(&spans[1..]), + Type::Any, + )]); } }; @@ -3425,12 +3412,12 @@ pub fn parse_source(working_set: &mut StateWorkingSet, lite_command: &LiteComman Ok(s) => s, Err(err) => { working_set.error(err.wrap(working_set, Span::concat(&spans[1..]))); - return Pipeline::from_vec(vec![Expression { - expr: Expr::Call(call), - span: Span::concat(&spans[1..]), - ty: Type::Any, - custom_completion: None, - }]); + return Pipeline::from_vec(vec![Expression::new( + working_set, + Expr::Call(call), + Span::concat(&spans[1..]), + Type::Any, + )]); } }; @@ -3439,7 +3426,7 @@ pub fn parse_source(working_set: &mut StateWorkingSet, lite_command: &LiteComman // Add the file to the stack of files being processed. if let Err(e) = working_set.files.push(path.clone().path_buf(), spans[1]) { working_set.error(e); - return garbage_pipeline(spans); + return garbage_pipeline(working_set, spans); } // This will load the defs from the file into the @@ -3463,38 +3450,38 @@ pub fn parse_source(working_set: &mut StateWorkingSet, lite_command: &LiteComman // after writing `source example.nu` call_with_block.set_parser_info( "block_id".to_string(), - Expression { - expr: Expr::Int(block_id as i64), - span: spans[1], - ty: Type::Any, - custom_completion: None, - }, + Expression::new( + working_set, + Expr::Int(block_id as i64), + spans[1], + Type::Any, + ), ); - return Pipeline::from_vec(vec![Expression { - expr: Expr::Call(call_with_block), - span: Span::concat(spans), - ty: Type::Any, - custom_completion: None, - }]); + return Pipeline::from_vec(vec![Expression::new( + working_set, + Expr::Call(call_with_block), + Span::concat(spans), + Type::Any, + )]); } } else { working_set.error(ParseError::SourcedFileNotFound(filename, spans[1])); } } - return Pipeline::from_vec(vec![Expression { - expr: Expr::Call(call), - span: Span::concat(spans), - ty: Type::Any, - custom_completion: None, - }]); + return Pipeline::from_vec(vec![Expression::new( + working_set, + Expr::Call(call), + Span::concat(spans), + Type::Any, + )]); } } working_set.error(ParseError::UnknownState( "internal error: source statement unparsable".into(), Span::concat(spans), )); - garbage_pipeline(spans) + garbage_pipeline(working_set, spans) } pub fn parse_where_expr(working_set: &mut StateWorkingSet, spans: &[Span]) -> Expression { @@ -3505,7 +3492,7 @@ pub fn parse_where_expr(working_set: &mut StateWorkingSet, spans: &[Span]) -> Ex "internal error: Wrong call name for 'where' command".into(), Span::concat(spans), )); - return garbage(Span::concat(spans)); + return garbage(working_set, Span::concat(spans)); } if spans.len() < 2 { @@ -3514,7 +3501,7 @@ pub fn parse_where_expr(working_set: &mut StateWorkingSet, spans: &[Span]) -> Ex Span::concat(spans), "where ".into(), )); - return garbage(Span::concat(spans)); + return garbage(working_set, Span::concat(spans)); } let call = match working_set.find_decl(b"where") { @@ -3529,16 +3516,11 @@ pub fn parse_where_expr(working_set: &mut StateWorkingSet, spans: &[Span]) -> Ex check_call(working_set, call_span, &decl.signature(), &call); let Ok(is_help) = has_flag_const(working_set, &call, "help") else { - return garbage(Span::concat(spans)); + return garbage(working_set, Span::concat(spans)); }; if starting_error_count != working_set.parse_errors.len() || is_help { - return Expression { - expr: Expr::Call(call), - span: call_span, - ty: output, - custom_completion: None, - }; + return Expression::new(working_set, Expr::Call(call), call_span, output); } call @@ -3548,16 +3530,16 @@ pub fn parse_where_expr(working_set: &mut StateWorkingSet, spans: &[Span]) -> Ex "internal error: 'where' declaration not found".into(), Span::concat(spans), )); - return garbage(Span::concat(spans)); + return garbage(working_set, Span::concat(spans)); } }; - Expression { - expr: Expr::Call(call), - span: Span::concat(spans), - ty: Type::Any, - custom_completion: None, - } + Expression::new( + working_set, + Expr::Call(call), + Span::concat(spans), + Type::Any, + ) } pub fn parse_where(working_set: &mut StateWorkingSet, lite_command: &LiteCommand) -> Pipeline { @@ -3599,11 +3581,11 @@ pub fn parse_register(working_set: &mut StateWorkingSet, lite_command: &LiteComm "internal error: Wrong call name for 'register' function".into(), Span::concat(spans), )); - return garbage_pipeline(spans); + return garbage_pipeline(working_set, spans); } if let Some(redirection) = lite_command.redirection.as_ref() { working_set.error(redirecting_builtin_error("register", redirection)); - return garbage_pipeline(spans); + return garbage_pipeline(working_set, spans); } // Parsing the spans and checking that they match the register signature @@ -3615,7 +3597,7 @@ pub fn parse_register(working_set: &mut StateWorkingSet, lite_command: &LiteComm "internal error: Register declaration not found".into(), Span::concat(spans), )); - return garbage_pipeline(spans); + return garbage_pipeline(working_set, spans); } Some(decl_id) => { let ParsedInternalCall { call, output } = @@ -3628,16 +3610,16 @@ pub fn parse_register(working_set: &mut StateWorkingSet, lite_command: &LiteComm check_call(working_set, call_span, &decl.signature(), &call); let Ok(is_help) = has_flag_const(working_set, &call, "help") else { - return garbage_pipeline(spans); + return garbage_pipeline(working_set, spans); }; if starting_error_count != working_set.parse_errors.len() || is_help { - return Pipeline::from_vec(vec![Expression { - expr: Expr::Call(call), - span: call_span, - ty: output, - custom_completion: None, - }]); + return Pipeline::from_vec(vec![Expression::new( + working_set, + Expr::Call(call), + call_span, + output, + )]); } (call, call_span) @@ -3718,12 +3700,12 @@ pub fn parse_register(working_set: &mut StateWorkingSet, lite_command: &LiteComm Ok(path) => Some(path), Err(err) => { working_set.error(err); - return Pipeline::from_vec(vec![Expression { - expr: Expr::Call(call), - span: call_span, - ty: Type::Any, - custom_completion: None, - }]); + return Pipeline::from_vec(vec![Expression::new( + working_set, + Expr::Call(call), + call_span, + Type::Any, + )]); } }, }; @@ -3799,12 +3781,12 @@ pub fn parse_register(working_set: &mut StateWorkingSet, lite_command: &LiteComm working_set.error(err); } - Pipeline::from_vec(vec![Expression { - expr: Expr::Call(call), - span: call_span, - ty: Type::Nothing, - custom_completion: None, - }]) + Pipeline::from_vec(vec![Expression::new( + working_set, + Expr::Call(call), + call_span, + Type::Nothing, + )]) } #[cfg(feature = "plugin")] @@ -3905,12 +3887,12 @@ pub fn parse_plugin_use(working_set: &mut StateWorkingSet, call: Box) -> P let call_span = call.span(); - Pipeline::from_vec(vec![Expression { - expr: Expr::Call(call), - span: call_span, - ty: Type::Nothing, - custom_completion: None, - }]) + Pipeline::from_vec(vec![Expression::new( + working_set, + Expr::Call(call), + call_span, + Type::Nothing, + )]) } pub fn find_dirs_var(working_set: &StateWorkingSet, var_name: &str) -> Option { diff --git a/crates/nu-parser/src/parser.rs b/crates/nu-parser/src/parser.rs index 830d8b81e0..149bce8958 100644 --- a/crates/nu-parser/src/parser.rs +++ b/crates/nu-parser/src/parser.rs @@ -23,12 +23,12 @@ use std::{ sync::Arc, }; -pub fn garbage(span: Span) -> Expression { - Expression::garbage(span) +pub fn garbage(working_set: &mut StateWorkingSet, span: Span) -> Expression { + Expression::garbage(working_set, span) } -pub fn garbage_pipeline(spans: &[Span]) -> Pipeline { - Pipeline::from_vec(vec![garbage(Span::concat(spans))]) +pub fn garbage_pipeline(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipeline { + Pipeline::from_vec(vec![garbage(working_set, Span::concat(spans))]) } fn is_identifier_byte(b: u8) -> bool { @@ -247,12 +247,12 @@ fn parse_external_arg(working_set: &mut StateWorkingSet, span: Span) -> External working_set.error(err); } - ExternalArgument::Regular(Expression { - expr: Expr::String(contents), + ExternalArgument::Regular(Expression::new( + working_set, + Expr::String(contents), span, - ty: Type::String, - custom_completion: None, - }) + Type::String, + )) } } @@ -280,12 +280,12 @@ pub fn parse_external_call(working_set: &mut StateWorkingSet, spans: &[Span]) -> working_set.error(err) } - Box::new(Expression { - expr: Expr::String(contents), - span: head_span, - ty: Type::String, - custom_completion: None, - }) + Box::new(Expression::new( + working_set, + Expr::String(contents), + head_span, + Type::String, + )) }; let args = spans[1..] @@ -293,12 +293,12 @@ pub fn parse_external_call(working_set: &mut StateWorkingSet, spans: &[Span]) -> .map(|&span| parse_external_arg(working_set, span)) .collect(); - Expression { - expr: Expr::ExternalCall(head, args), - span: Span::concat(spans), - ty: Type::Any, - custom_completion: None, - } + Expression::new( + working_set, + Expr::ExternalCall(head, args), + Span::concat(spans), + Type::Any, + ) } fn ensure_flag_arg_type( @@ -319,7 +319,7 @@ fn ensure_flag_arg_type( item: arg_name, span: long_name_span, }, - Expression::garbage(arg.span), + Expression::garbage(working_set, arg.span), ) } else { ( @@ -650,7 +650,7 @@ pub fn parse_multispan_value( )); } - Expression::garbage(span) + Expression::garbage(working_set, span) } SyntaxShape::Expression => { trace!("parsing: expression"); @@ -701,14 +701,14 @@ pub fn parse_multispan_value( let keyword = Keyword { keyword: keyword.as_slice().into(), span: spans[*spans_idx - 1], - expr: Expression::garbage(arg_span), - }; - return Expression { - expr: Expr::Keyword(Box::new(keyword)), - span: arg_span, - ty: Type::Any, - custom_completion: None, + expr: Expression::garbage(working_set, arg_span), }; + return Expression::new( + working_set, + Expr::Keyword(Box::new(keyword)), + arg_span, + Type::Any, + ); } let keyword = Keyword { @@ -717,12 +717,12 @@ pub fn parse_multispan_value( expr: parse_multispan_value(working_set, spans, spans_idx, arg), }; - Expression { - ty: keyword.expr.ty.clone(), - expr: Expr::Keyword(Box::new(keyword)), - span: arg_span, - custom_completion: None, - } + Expression::new( + working_set, + Expr::Keyword(Box::new(keyword.clone())), + arg_span, + keyword.expr.ty, + ) } _ => { // All other cases are single-span values @@ -738,25 +738,6 @@ pub struct ParsedInternalCall { pub output: Type, } -fn attach_parser_info_builtin(working_set: &StateWorkingSet, name: &str, call: &mut Call) { - match name { - "use" | "overlay use" | "source-env" | "nu-check" => { - if let Some(var_id) = find_dirs_var(working_set, LIB_DIRS_VAR) { - call.set_parser_info( - DIR_VAR_PARSER_INFO.to_owned(), - Expression { - expr: Expr::Var(var_id), - span: call.head, - ty: Type::Any, - custom_completion: None, - }, - ); - } - } - _ => {} - } -} - pub fn parse_internal_call( working_set: &mut StateWorkingSet, command_span: Span, @@ -768,14 +749,23 @@ pub fn parse_internal_call( let mut call = Call::new(command_span); call.decl_id = decl_id; call.head = command_span; + let _ = working_set.add_span(call.head); let decl = working_set.get_decl(decl_id); let signature = decl.signature(); let output = signature.get_output_type(); - if decl.is_builtin() { - attach_parser_info_builtin(working_set, decl.name(), &mut call); - } + // storing the var ID for later due to borrowing issues + let lib_dirs_var_id = if decl.is_builtin() { + match decl.name() { + "use" | "overlay use" | "source-env" | "nu-check" => { + find_dirs_var(working_set, LIB_DIRS_VAR) + } + _ => None, + } + } else { + None + }; // The index into the positional parameter in the definition let mut positional_idx = 0; @@ -807,6 +797,13 @@ pub fn parse_internal_call( } } + if let Some(var_id) = lib_dirs_var_id { + call.set_parser_info( + DIR_VAR_PARSER_INFO.to_owned(), + Expression::new(working_set, Expr::Var(var_id), call.head, Type::Any), + ); + } + if signature.creates_scope { working_set.enter_scope(); } @@ -873,6 +870,8 @@ pub fn parse_internal_call( call.add_unknown(arg); } else { for flag in short_flags { + let _ = working_set.add_span(spans[spans_idx]); + if let Some(arg_shape) = flag.arg { if let Some(arg) = spans.get(spans_idx + 1) { let arg = parse_value(working_set, *arg, &arg_shape); @@ -951,14 +950,14 @@ pub fn parse_internal_call( signature.call_signature(), arg_span, )); - call.add_positional(Expression::garbage(arg_span)); + call.add_positional(Expression::garbage(working_set, arg_span)); } else if positional_idx < signature.required_positional.len() { working_set.error(ParseError::MissingPositional( signature.required_positional[positional_idx].name.clone(), Span::new(spans[spans_idx].start, spans[spans_idx].start), signature.call_signature(), )); - call.add_positional(Expression::garbage(arg_span)); + call.add_positional(Expression::garbage(working_set, arg_span)); } else { let rest_shape = match &signature.rest_positional { Some(arg) => arg.shape.clone(), @@ -1015,7 +1014,7 @@ pub fn parse_internal_call( arg.ty, arg.span, )); - Expression::garbage(arg.span) + Expression::garbage(working_set, arg.span) } else { arg }; @@ -1026,7 +1025,7 @@ pub fn parse_internal_call( call.add_unknown(arg); } else { - call.add_positional(Expression::garbage(arg_span)); + call.add_positional(Expression::garbage(working_set, arg_span)); working_set.error(ParseError::ExtraPositional( signature.call_signature(), arg_span, @@ -1056,7 +1055,7 @@ pub fn parse_call(working_set: &mut StateWorkingSet, spans: &[Span], head: Span) "Encountered command with zero spans".into(), Span::concat(spans), )); - return garbage(head); + return garbage(working_set, head); } let mut pos = 0; @@ -1118,7 +1117,7 @@ pub fn parse_call(working_set: &mut StateWorkingSet, spans: &[Span], head: Span) "Incomplete statement".into(), Span::concat(spans), )); - return garbage(Span::concat(spans)); + return garbage(working_set, Span::concat(spans)); } } @@ -1129,6 +1128,7 @@ pub fn parse_call(working_set: &mut StateWorkingSet, spans: &[Span], head: Span) if let Expression { expr: Expr::ExternalCall(head, args), span: _, + span_id: _, ty, custom_completion, } = &alias.clone().wrapped_call @@ -1144,12 +1144,15 @@ pub fn parse_call(working_set: &mut StateWorkingSet, spans: &[Span], head: Span) final_args.push(arg); } - return Expression { - expr: Expr::ExternalCall(head, final_args.into()), - span: Span::concat(spans), - ty: ty.clone(), - custom_completion: *custom_completion, - }; + let mut expression = Expression::new( + working_set, + Expr::ExternalCall(head, final_args.into()), + Span::concat(spans), + ty.clone(), + ); + + expression.custom_completion = *custom_completion; + return expression; } else { trace!("parsing: alias of internal call"); parse_internal_call( @@ -1169,12 +1172,12 @@ pub fn parse_call(working_set: &mut StateWorkingSet, spans: &[Span], head: Span) ) }; - Expression { - expr: Expr::Call(parsed_call.call), - span: Span::concat(spans), - ty: parsed_call.output, - custom_completion: None, - } + Expression::new( + working_set, + Expr::Call(parsed_call.call), + Span::concat(spans), + parsed_call.output, + ) } else { // We might be parsing left-unbounded range ("..10") let bytes = working_set.get_span_contents(spans[0]); @@ -1208,7 +1211,7 @@ pub fn parse_binary(working_set: &mut StateWorkingSet, span: Span) -> Expression parse_binary_with_base(working_set, span, 2, 8, b"0b[", b"]") } else { working_set.error(ParseError::Expected("binary", span)); - garbage(span) + garbage(working_set, span) } } @@ -1254,7 +1257,7 @@ fn parse_binary_with_base( | TokenContents::OutErrGreaterThan | TokenContents::OutErrGreaterGreaterThan => { working_set.error(ParseError::Expected("binary", span)); - return garbage(span); + return garbage(working_set, span); } TokenContents::Comment | TokenContents::Semicolon | TokenContents::Eol => {} } @@ -1275,28 +1278,21 @@ fn parse_binary_with_base( let str = String::from_utf8_lossy(&binary_value).to_string(); match decode_with_base(&str, base, min_digits_per_byte) { - Ok(v) => { - return Expression { - expr: Expr::Binary(v), - span, - ty: Type::Binary, - custom_completion: None, - } - } + Ok(v) => return Expression::new(working_set, Expr::Binary(v), span, Type::Binary), Err(x) => { working_set.error(ParseError::IncorrectValue( "not a binary value".into(), span, x.to_string(), )); - return garbage(span); + return garbage(working_set, span); } } } } working_set.error(ParseError::Expected("binary", span)); - garbage(span) + garbage(working_set, span) } fn decode_with_base(s: &str, base: u32, digits_per_byte: usize) -> Result, ParseIntError> { @@ -1327,12 +1323,7 @@ pub fn parse_int(working_set: &mut StateWorkingSet, span: Span) -> Expression { radix: u32, ) -> Expression { if let Ok(num) = i64::from_str_radix(token, radix) { - Expression { - expr: Expr::Int(num), - span, - ty: Type::Int, - custom_completion: None, - } + Expression::new(working_set, Expr::Int(num), span, Type::Int) } else { working_set.error(ParseError::InvalidLiteral( format!("invalid digits for radix {}", radix), @@ -1340,7 +1331,7 @@ pub fn parse_int(working_set: &mut StateWorkingSet, span: Span) -> Expression { span, )); - garbage(span) + garbage(working_set, span) } } @@ -1348,7 +1339,7 @@ pub fn parse_int(working_set: &mut StateWorkingSet, span: Span) -> Expression { if token.is_empty() { working_set.error(ParseError::Expected("int", span)); - return garbage(span); + return garbage(working_set, span); } if let Some(num) = token.strip_prefix("0b") { @@ -1358,15 +1349,10 @@ pub fn parse_int(working_set: &mut StateWorkingSet, span: Span) -> Expression { } else if let Some(num) = token.strip_prefix("0x") { extract_int(working_set, num, span, 16) } else if let Ok(num) = token.parse::() { - Expression { - expr: Expr::Int(num), - span, - ty: Type::Int, - custom_completion: None, - } + Expression::new(working_set, Expr::Int(num), span, Type::Int) } else { working_set.error(ParseError::Expected("int", span)); - garbage(span) + garbage(working_set, span) } } @@ -1375,16 +1361,11 @@ pub fn parse_float(working_set: &mut StateWorkingSet, span: Span) -> Expression let token = strip_underscores(token); if let Ok(x) = token.parse::() { - Expression { - expr: Expr::Float(x), - span, - ty: Type::Float, - custom_completion: None, - } + Expression::new(working_set, Expr::Float(x), span, Type::Float) } else { working_set.error(ParseError::Expected("float", span)); - garbage(span) + garbage(working_set, span) } } @@ -1410,7 +1391,7 @@ pub fn parse_number(working_set: &mut StateWorkingSet, span: Span) -> Expression working_set.parse_errors.truncate(starting_error_count); working_set.error(ParseError::Expected("number", span)); - garbage(span) + garbage(working_set, span) } pub fn parse_range(working_set: &mut StateWorkingSet, span: Span) -> Expression { @@ -1429,12 +1410,12 @@ pub fn parse_range(working_set: &mut StateWorkingSet, span: Span) -> Expression s } else { working_set.error(ParseError::NonUtf8(span)); - return garbage(span); + return garbage(working_set, span); }; if !token.contains("..") { working_set.error(ParseError::Expected("at least one range bound set", span)); - return garbage(span); + return garbage(working_set, span); } // First, figure out what exact operators are used and determine their positions @@ -1448,7 +1429,7 @@ pub fn parse_range(working_set: &mut StateWorkingSet, span: Span) -> Expression "one range operator ('..' or '..<') and optionally one next operator ('..')", span, )); - return garbage(span); + return garbage(working_set, span); } }; // Avoid calling sub-parsers on unmatched parens, to prevent quadratic time on things like ((((1..2)))) @@ -1463,7 +1444,7 @@ pub fn parse_range(working_set: &mut StateWorkingSet, span: Span) -> Expression ); if let Some(_err) = err { working_set.error(ParseError::Expected("Valid expression before ..", span)); - return garbage(span); + return garbage(working_set, span); } } @@ -1480,7 +1461,7 @@ pub fn parse_range(working_set: &mut StateWorkingSet, span: Span) -> Expression "inclusive operator preceding second range bound", span, )); - return garbage(span); + return garbage(working_set, span); } } else { let op_str = if token.contains("..=") { "..=" } else { ".." }; @@ -1513,7 +1494,7 @@ pub fn parse_range(working_set: &mut StateWorkingSet, span: Span) -> Expression if let (None, None) = (&from, &to) { working_set.error(ParseError::Expected("at least one range bound set", span)); - return garbage(span); + return garbage(working_set, span); } let (next, next_op_span) = if let Some(pos) = next_op_pos { @@ -1541,12 +1522,7 @@ pub fn parse_range(working_set: &mut StateWorkingSet, span: Span) -> Expression operator, }; - Expression { - expr: Expr::Range(Box::new(range)), - span, - ty: Type::Range, - custom_completion: None, - } + Expression::new(working_set, Expr::Range(Box::new(range)), span, Type::Range) } pub(crate) fn parse_dollar_expr(working_set: &mut StateWorkingSet, span: Span) -> Expression { @@ -1587,7 +1563,7 @@ pub fn parse_raw_string(working_set: &mut StateWorkingSet, span: Span) -> Expres sharp_cnt } else { working_set.error(ParseError::Expected("r#", span)); - return garbage(span); + return garbage(working_set, span); }; let expect_postfix_sharp_cnt = prefix_sharp_cnt; // check the length of whole raw string. @@ -1595,7 +1571,7 @@ pub fn parse_raw_string(working_set: &mut StateWorkingSet, span: Span) -> Expres // 1(r) + prefix_sharp_cnt + 1(') + 1(') + postfix_sharp characters if bytes.len() < prefix_sharp_cnt + expect_postfix_sharp_cnt + 3 { working_set.error(ParseError::Unclosed('\''.into(), span)); - return garbage(span); + return garbage(working_set, span); } // check for unbalanced # and single quotes. @@ -1606,27 +1582,22 @@ pub fn parse_raw_string(working_set: &mut StateWorkingSet, span: Span) -> Expres "postfix #".to_string(), span, )); - return garbage(span); + return garbage(working_set, span); } // check for unblanaced single quotes. if bytes[1 + prefix_sharp_cnt] != b'\'' || bytes[bytes.len() - expect_postfix_sharp_cnt - 1] != b'\'' { working_set.error(ParseError::Unclosed('\''.into(), span)); - return garbage(span); + return garbage(working_set, span); } let bytes = &bytes[prefix_sharp_cnt + 1 + 1..bytes.len() - 1 - prefix_sharp_cnt]; if let Ok(token) = String::from_utf8(bytes.into()) { - Expression { - expr: Expr::RawString(token), - span, - ty: Type::String, - custom_completion: None, - } + Expression::new(working_set, Expr::RawString(token), span, Type::String) } else { working_set.error(ParseError::Expected("utf8 raw-string", span)); - garbage(span) + garbage(working_set, span) } } @@ -1670,7 +1641,7 @@ pub fn parse_brace_expr( format!("non-block value: {shape}"), span, )); - return Expression::garbage(span); + return Expression::garbage(working_set, span); } let bytes = working_set.get_span_contents(Span::new(span.start + 1, span.end - 1)); @@ -1721,7 +1692,7 @@ pub fn parse_brace_expr( span, )); - Expression::garbage(span) + Expression::garbage(working_set, span) } } @@ -1796,12 +1767,12 @@ pub fn parse_string_interpolation(working_set: &mut StateWorkingSet, span: Span) working_set.error(err); } - output.push(Expression { - expr: Expr::String(String::from_utf8_lossy(&str_contents).to_string()), + output.push(Expression::new( + working_set, + Expr::String(String::from_utf8_lossy(&str_contents).to_string()), span, - ty: Type::String, - custom_completion: None, - }); + Type::String, + )); token_start = b; } } @@ -1866,12 +1837,12 @@ pub fn parse_string_interpolation(working_set: &mut StateWorkingSet, span: Span) working_set.error(err); } - output.push(Expression { - expr: Expr::String(String::from_utf8_lossy(&str_contents).to_string()), + output.push(Expression::new( + working_set, + Expr::String(String::from_utf8_lossy(&str_contents).to_string()), span, - ty: Type::String, - custom_completion: None, - }); + Type::String, + )); } } InterpolationMode::Expression => { @@ -1884,38 +1855,38 @@ pub fn parse_string_interpolation(working_set: &mut StateWorkingSet, span: Span) } } - Expression { - expr: Expr::StringInterpolation(output), + Expression::new( + working_set, + Expr::StringInterpolation(output), span, - ty: Type::String, - custom_completion: None, - } + Type::String, + ) } pub fn parse_variable_expr(working_set: &mut StateWorkingSet, span: Span) -> Expression { let contents = working_set.get_span_contents(span); if contents == b"$nu" { - return Expression { - expr: Expr::Var(nu_protocol::NU_VARIABLE_ID), + return Expression::new( + working_set, + Expr::Var(nu_protocol::NU_VARIABLE_ID), span, - ty: Type::Any, - custom_completion: None, - }; + Type::Any, + ); } else if contents == b"$in" { - return Expression { - expr: Expr::Var(nu_protocol::IN_VARIABLE_ID), + return Expression::new( + working_set, + Expr::Var(nu_protocol::IN_VARIABLE_ID), span, - ty: Type::Any, - custom_completion: None, - }; + Type::Any, + ); } else if contents == b"$env" { - return Expression { - expr: Expr::Var(nu_protocol::ENV_VARIABLE_ID), + return Expression::new( + working_set, + Expr::Var(nu_protocol::ENV_VARIABLE_ID), span, - ty: Type::Any, - custom_completion: None, - }; + Type::Any, + ); } let name = if contents.starts_with(b"$") { @@ -1925,20 +1896,20 @@ pub fn parse_variable_expr(working_set: &mut StateWorkingSet, span: Span) -> Exp }; if let Some(id) = parse_variable(working_set, span) { - Expression { - expr: Expr::Var(id), + Expression::new( + working_set, + Expr::Var(id), span, - ty: working_set.get_variable(id).ty.clone(), - custom_completion: None, - } + working_set.get_variable(id).ty.clone(), + ) } else if working_set.get_env_var(&name).is_some() { working_set.error(ParseError::EnvVarNotVar(name, span)); - garbage(span) + garbage(working_set, span) } else { let ws = &*working_set; let suggestion = DidYouMean::new(&ws.list_variables(), ws.get_span_contents(span)); working_set.error(ParseError::VariableNotFound(suggestion, span)); - garbage(span) + garbage(working_set, span) } } @@ -2051,12 +2022,12 @@ pub fn parse_simple_cell_path(working_set: &mut StateWorkingSet, span: Span) -> let cell_path = parse_cell_path(working_set, tokens, false); - Expression { - expr: Expr::CellPath(CellPath { members: cell_path }), + Expression::new( + working_set, + Expr::CellPath(CellPath { members: cell_path }), span, - ty: Type::CellPath, - custom_completion: None, - } + Type::CellPath, + ) } pub fn parse_full_cell_path( @@ -2111,12 +2082,7 @@ pub fn parse_full_cell_path( tokens.next(); ( - Expression { - expr: Expr::Subexpression(block_id), - span: head_span, - ty, - custom_completion: None, - }, + Expression::new(working_set, Expr::Subexpression(block_id), head_span, ty), true, ) } else if bytes.starts_with(b"[") { @@ -2145,12 +2111,7 @@ pub fn parse_full_cell_path( } else if let Some(var_id) = implicit_head { trace!("parsing: implicit head of full cell path"); ( - Expression { - expr: Expr::Var(var_id), - span: head.span, - ty: Type::Any, - custom_completion: None, - }, + Expression::new(working_set, Expr::Var(var_id), head.span, Type::Any), false, ) } else { @@ -2159,26 +2120,27 @@ pub fn parse_full_cell_path( String::from_utf8_lossy(bytes).to_string(), span, )); - return garbage(span); + return garbage(working_set, span); }; let tail = parse_cell_path(working_set, tokens, expect_dot); + // FIXME: Get the type of the data at the tail using follow_cell_path() (or something) + let ty = if !tail.is_empty() { + // Until the aforementioned fix is implemented, this is necessary to allow mutable list upserts + // such as $a.1 = 2 to work correctly. + Type::Any + } else { + head.ty.clone() + }; - Expression { - // FIXME: Get the type of the data at the tail using follow_cell_path() (or something) - ty: if !tail.is_empty() { - // Until the aforementioned fix is implemented, this is necessary to allow mutable list upserts - // such as $a.1 = 2 to work correctly. - Type::Any - } else { - head.ty.clone() - }, - expr: Expr::FullCellPath(Box::new(FullCellPath { head, tail })), - span: full_cell_span, - custom_completion: None, - } + Expression::new( + working_set, + Expr::FullCellPath(Box::new(FullCellPath { head, tail })), + full_cell_span, + ty, + ) } else { - garbage(span) + garbage(working_set, span) } } @@ -2191,16 +2153,16 @@ pub fn parse_directory(working_set: &mut StateWorkingSet, span: Span) -> Express if err.is_none() { trace!("-- found {}", token); - Expression { - expr: Expr::Directory(token, quoted), + Expression::new( + working_set, + Expr::Directory(token, quoted), span, - ty: Type::String, - custom_completion: None, - } + Type::String, + ) } else { working_set.error(ParseError::Expected("directory", span)); - garbage(span) + garbage(working_set, span) } } @@ -2213,18 +2175,19 @@ pub fn parse_filepath(working_set: &mut StateWorkingSet, span: Span) -> Expressi if err.is_none() { trace!("-- found {}", token); - Expression { - expr: Expr::Filepath(token, quoted), + Expression::new( + working_set, + Expr::Filepath(token, quoted), span, - ty: Type::String, - custom_completion: None, - } + Type::String, + ) } else { working_set.error(ParseError::Expected("filepath", span)); - garbage(span) + garbage(working_set, span) } } + /// Parse a datetime type, eg '2022-02-02' pub fn parse_datetime(working_set: &mut StateWorkingSet, span: Span) -> Expression { trace!("parsing: datetime"); @@ -2239,45 +2202,30 @@ pub fn parse_datetime(working_set: &mut StateWorkingSet, span: Span) -> Expressi || bytes[4] != b'-' { working_set.error(ParseError::Expected("datetime", span)); - return garbage(span); + return garbage(working_set, span); } let token = String::from_utf8_lossy(bytes).to_string(); if let Ok(datetime) = chrono::DateTime::parse_from_rfc3339(&token) { - return Expression { - expr: Expr::DateTime(datetime), - span, - ty: Type::Date, - custom_completion: None, - }; + return Expression::new(working_set, Expr::DateTime(datetime), span, Type::Date); } // Just the date 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), - span, - ty: Type::Date, - custom_completion: None, - }; + return Expression::new(working_set, Expr::DateTime(datetime), span, Type::Date); } // Date and time, assume UTC let datetime = token + "+00:00"; if let Ok(datetime) = chrono::DateTime::parse_from_rfc3339(&datetime) { - return Expression { - expr: Expr::DateTime(datetime), - span, - ty: Type::Date, - custom_completion: None, - }; + return Expression::new(working_set, Expr::DateTime(datetime), span, Type::Date); } working_set.error(ParseError::Expected("datetime", span)); - garbage(span) + garbage(working_set, span) } /// Parse a duration type, eg '10day' @@ -2287,14 +2235,17 @@ pub fn parse_duration(working_set: &mut StateWorkingSet, span: Span) -> Expressi let bytes = working_set.get_span_contents(span); match parse_unit_value(bytes, span, DURATION_UNIT_GROUPS, Type::Duration, |x| x) { - Some(Ok(expr)) => expr, + Some(Ok(expr)) => { + let span_id = working_set.add_span(span); + expr.with_span_id(span_id) + } Some(Err(mk_err_for)) => { working_set.error(mk_err_for("duration")); - garbage(span) + garbage(working_set, span) } None => { working_set.error(ParseError::Expected("duration with valid units", span)); - garbage(span) + garbage(working_set, span) } } } @@ -2308,20 +2259,23 @@ pub fn parse_filesize(working_set: &mut StateWorkingSet, span: Span) -> Expressi // the hex digit `b` might be mistaken for the unit `b`, so check that first if bytes.starts_with(b"0x") { working_set.error(ParseError::Expected("filesize with valid units", span)); - return garbage(span); + return garbage(working_set, span); } match parse_unit_value(bytes, span, FILESIZE_UNIT_GROUPS, Type::Filesize, |x| { x.to_ascii_uppercase() }) { - Some(Ok(expr)) => expr, + Some(Ok(expr)) => { + let span_id = working_set.add_span(span); + expr.with_span_id(span_id) + } Some(Err(mk_err_for)) => { working_set.error(mk_err_for("filesize")); - garbage(span) + garbage(working_set, span) } None => { working_set.error(ParseError::Expected("filesize with valid units", span)); - garbage(span) + garbage(working_set, span) } } } @@ -2379,23 +2333,13 @@ pub fn parse_unit_value<'res>( trace!("-- found {} {:?}", num, unit); let value = ValueWithUnit { - expr: Expression { - expr: Expr::Int(num), - span: lhs_span, - ty: Type::Number, - custom_completion: None, - }, + expr: Expression::new_unknown(Expr::Int(num), lhs_span, Type::Number), unit: Spanned { item: unit, span: unit_span, }, }; - let expr = Expression { - expr: Expr::ValueWithUnit(Box::new(value)), - span, - ty, - custom_completion: None, - }; + let expr = Expression::new_unknown(Expr::ValueWithUnit(Box::new(value)), span, ty); Some(Ok(expr)) } else { @@ -2487,16 +2431,16 @@ pub fn parse_glob_pattern(working_set: &mut StateWorkingSet, span: Span) -> Expr if err.is_none() { trace!("-- found {}", token); - Expression { - expr: Expr::GlobPattern(token, quoted), + Expression::new( + working_set, + Expr::GlobPattern(token, quoted), span, - ty: Type::Glob, - custom_completion: None, - } + Type::Glob, + ) } else { working_set.error(ParseError::Expected("glob pattern string", span)); - garbage(span) + garbage(working_set, span) } } @@ -2719,7 +2663,7 @@ pub fn parse_string(working_set: &mut StateWorkingSet, span: Span) -> Expression if bytes.is_empty() { working_set.error(ParseError::Expected("String", span)); - return Expression::garbage(span); + return Expression::garbage(working_set, span); } // Check for bare word interpolation @@ -2732,12 +2676,7 @@ pub fn parse_string(working_set: &mut StateWorkingSet, span: Span) -> Expression working_set.error(err); } - Expression { - expr: Expr::String(s), - span, - ty: Type::String, - custom_completion: None, - } + Expression::new(working_set, Expr::String(s), span, Type::String) } fn is_quoted(bytes: &[u8]) -> bool { @@ -2759,11 +2698,11 @@ pub fn parse_string_strict(working_set: &mut StateWorkingSet, span: Span) -> Exp }; if bytes.starts_with(b"\"") && (bytes.len() == 1 || !bytes.ends_with(b"\"")) { working_set.error(ParseError::Unclosed("\"".into(), span)); - return garbage(span); + return garbage(working_set, span); } if bytes.starts_with(b"\'") && (bytes.len() == 1 || !bytes.ends_with(b"\'")) { working_set.error(ParseError::Unclosed("\'".into(), span)); - return garbage(span); + return garbage(working_set, span); } } @@ -2783,27 +2722,17 @@ pub fn parse_string_strict(working_set: &mut StateWorkingSet, span: Span) -> Exp trace!("-- found {}", token); if quoted { - Expression { - expr: Expr::String(token), - span, - ty: Type::String, - custom_completion: None, - } + Expression::new(working_set, Expr::String(token), span, Type::String) } else if token.contains(' ') { working_set.error(ParseError::Expected("string", span)); - garbage(span) + garbage(working_set, span) } else { - Expression { - expr: Expr::String(token), - span, - ty: Type::String, - custom_completion: None, - } + Expression::new(working_set, Expr::String(token), span, Type::String) } } else { working_set.error(ParseError::Expected("string", span)); - garbage(span) + garbage(working_set, span) } } @@ -2813,7 +2742,7 @@ pub fn parse_import_pattern(working_set: &mut StateWorkingSet, spans: &[Span]) - "needs at least one component of import pattern".to_string(), Span::concat(spans), )); - return garbage(Span::concat(spans)); + return garbage(working_set, Span::concat(spans)); }; let head_expr = parse_value(working_set, *head_span, &SyntaxShape::Any); @@ -2823,12 +2752,12 @@ pub fn parse_import_pattern(working_set: &mut StateWorkingSet, spans: &[Span]) - Ok(s) => (working_set.find_module(s.as_bytes()), s.into_bytes()), Err(err) => { working_set.error(err.wrap(working_set, Span::concat(spans))); - return garbage(Span::concat(spans)); + return garbage(working_set, Span::concat(spans)); } }, Err(err) => { working_set.error(err.wrap(working_set, Span::concat(spans))); - return garbage(Span::concat(spans)); + return garbage(working_set, Span::concat(spans)); } }; @@ -2860,12 +2789,12 @@ pub fn parse_import_pattern(working_set: &mut StateWorkingSet, spans: &[Span]) - ), prev_span, )); - return Expression { - expr: Expr::ImportPattern(Box::new(import_pattern)), - span: prev_span, - ty: Type::List(Box::new(Type::String)), - custom_completion: None, - }; + return Expression::new( + working_set, + Expr::ImportPattern(Box::new(import_pattern)), + prev_span, + Type::List(Box::new(Type::String)), + ); } let tail = working_set.get_span_contents(*tail_span); @@ -2906,12 +2835,12 @@ pub fn parse_import_pattern(working_set: &mut StateWorkingSet, spans: &[Span]) - .push(ImportPatternMember::List { names: output }); } else { working_set.error(ParseError::ExportNotFound(result.span)); - return Expression { - expr: Expr::ImportPattern(Box::new(import_pattern)), - span: Span::concat(spans), - ty: Type::List(Box::new(Type::String)), - custom_completion: None, - }; + return Expression::new( + working_set, + Expr::ImportPattern(Box::new(import_pattern)), + Span::concat(spans), + Type::List(Box::new(Type::String)), + ); } leaf_member_span = Some(*tail_span); @@ -2926,12 +2855,12 @@ pub fn parse_import_pattern(working_set: &mut StateWorkingSet, spans: &[Span]) - } } - Expression { - expr: Expr::ImportPattern(Box::new(import_pattern)), - span: Span::concat(&spans[1..]), - ty: Type::List(Box::new(Type::String)), - custom_completion: None, - } + Expression::new( + working_set, + Expr::ImportPattern(Box::new(import_pattern)), + Span::concat(&spans[1..]), + Type::List(Box::new(Type::String)), + ) } /// Parse `spans[spans_idx..]` into a variable, with optional type annotation. @@ -2952,7 +2881,7 @@ pub fn parse_var_with_opt_type( || bytes.contains(&b'`') { working_set.error(ParseError::VariableNotValid(spans[*spans_idx])); - return (garbage(spans[*spans_idx]), None); + return (garbage(working_set, spans[*spans_idx]), None); } if bytes.ends_with(b":") { @@ -2982,18 +2911,18 @@ pub fn parse_var_with_opt_type( "valid variable name", spans[*spans_idx - 1], )); - return (garbage(spans[*spans_idx - 1]), None); + return (garbage(working_set, spans[*spans_idx - 1]), None); } let id = working_set.add_variable(var_name, spans[*spans_idx - 1], ty.clone(), mutable); ( - Expression { - expr: Expr::VarDecl(id), - span: Span::concat(&spans[span_beginning..*spans_idx + 1]), - ty: ty.clone(), - custom_completion: None, - }, + Expression::new( + working_set, + Expr::VarDecl(id), + Span::concat(&spans[span_beginning..*spans_idx + 1]), + ty.clone(), + ), Some(ty), ) } else { @@ -3004,19 +2933,14 @@ pub fn parse_var_with_opt_type( "valid variable name", spans[*spans_idx], )); - return (garbage(spans[*spans_idx]), None); + return (garbage(working_set, spans[*spans_idx]), None); } let id = working_set.add_variable(var_name, spans[*spans_idx], Type::Any, mutable); working_set.error(ParseError::MissingType(spans[*spans_idx])); ( - Expression { - expr: Expr::VarDecl(id), - span: spans[*spans_idx], - ty: Type::Any, - custom_completion: None, - }, + Expression::new(working_set, Expr::VarDecl(id), spans[*spans_idx], Type::Any), None, ) } @@ -3028,7 +2952,7 @@ pub fn parse_var_with_opt_type( "valid variable name", spans[*spans_idx], )); - return (garbage(spans[*spans_idx]), None); + return (garbage(working_set, spans[*spans_idx]), None); } let id = working_set.add_variable( @@ -3039,12 +2963,7 @@ pub fn parse_var_with_opt_type( ); ( - Expression { - expr: Expr::VarDecl(id), - span: spans[*spans_idx], - ty: Type::Any, - custom_completion: None, - }, + Expression::new(working_set, Expr::VarDecl(id), spans[*spans_idx], Type::Any), None, ) } @@ -3199,12 +3118,7 @@ pub fn parse_row_condition(working_set: &mut StateWorkingSet, spans: &[Span]) -> } }; - Expression { - ty: Type::Bool, - span, - expr: Expr::RowCondition(block_id), - custom_completion: None, - } + Expression::new(working_set, Expr::RowCondition(block_id), span, Type::Bool) } pub fn parse_signature(working_set: &mut StateWorkingSet, span: Span) -> Expression { @@ -3222,7 +3136,7 @@ pub fn parse_signature(working_set: &mut StateWorkingSet, span: Span) -> Express start += 1; } else { working_set.error(ParseError::Expected("[ or (", Span::new(start, start + 1))); - return garbage(span); + return garbage(working_set, span); } if (has_paren && bytes.ends_with(b")")) || (!has_paren && bytes.ends_with(b"]")) { @@ -3233,12 +3147,7 @@ pub fn parse_signature(working_set: &mut StateWorkingSet, span: Span) -> Express let sig = parse_signature_helper(working_set, Span::new(start, end)); - Expression { - expr: Expr::Signature(sig), - span, - ty: Type::Signature, - custom_completion: None, - } + Expression::new(working_set, Expr::Signature(sig), span, Type::Signature) } pub fn parse_signature_helper(working_set: &mut StateWorkingSet, span: Span) -> Box { @@ -3939,16 +3848,16 @@ pub fn parse_list_expression( } } - Expression { - expr: Expr::List(args), + Expression::new( + working_set, + Expr::List(args), span, - ty: Type::List(Box::new(if let Some(ty) = contained_type { + Type::List(Box::new(if let Some(ty) = contained_type { ty } else { Type::Any })), - custom_completion: None, - } + ) } fn parse_table_row( @@ -4094,12 +4003,7 @@ fn parse_table_expression(working_set: &mut StateWorkingSet, span: Span) -> Expr rows: rows.into_iter().map(Into::into).collect(), }; - Expression { - expr: Expr::Table(table), - span, - ty, - custom_completion: None, - } + Expression::new(working_set, Expr::Table(table), span, ty) } fn table_type(head: &[Expression], rows: &[Vec]) -> (Type, Vec) { @@ -4156,7 +4060,7 @@ pub fn parse_block_expression(working_set: &mut StateWorkingSet, span: Span) -> start += 1; } else { working_set.error(ParseError::Expected("block", span)); - return garbage(span); + return garbage(working_set, span); } if bytes.ends_with(b"}") { end -= 1; @@ -4199,12 +4103,7 @@ pub fn parse_block_expression(working_set: &mut StateWorkingSet, span: Span) -> let block_id = working_set.add_block(Arc::new(output)); - Expression { - expr: Expr::Block(block_id), - span, - ty: Type::Block, - custom_completion: None, - } + Expression::new(working_set, Expr::Block(block_id), span, Type::Block) } pub fn parse_match_block_expression(working_set: &mut StateWorkingSet, span: Span) -> Expression { @@ -4217,7 +4116,7 @@ pub fn parse_match_block_expression(working_set: &mut StateWorkingSet, span: Spa start += 1; } else { working_set.error(ParseError::Expected("closure", span)); - return garbage(span); + return garbage(working_set, span); } if bytes.ends_with(b"}") { end -= 1; @@ -4333,7 +4232,7 @@ pub fn parse_match_block_expression(working_set: &mut StateWorkingSet, span: Spa if output.get(position).is_none() { working_set.error(mk_err()); - return garbage(span); + return garbage(working_set, span); }; let (tokens, found) = if let Some((pos, _)) = output[position..] @@ -4342,7 +4241,7 @@ pub fn parse_match_block_expression(working_set: &mut StateWorkingSet, span: Spa { if position + pos == position { working_set.error(mk_err()); - return garbage(span); + return garbage(working_set, span); } (&output[position..position + pos], true) @@ -4397,12 +4296,12 @@ pub fn parse_match_block_expression(working_set: &mut StateWorkingSet, span: Spa output_matches.push((pattern, result)); } - Expression { - expr: Expr::MatchBlock(output_matches), + Expression::new( + working_set, + Expr::MatchBlock(output_matches), span, - ty: Type::Any, - custom_completion: None, - } + Type::Any, + ) } pub fn parse_closure_expression( @@ -4421,7 +4320,7 @@ pub fn parse_closure_expression( start += 1; } else { working_set.error(ParseError::Expected("closure", span)); - return garbage(span); + return garbage(working_set, span); } if bytes.ends_with(b"}") { end -= 1; @@ -4526,12 +4425,7 @@ pub fn parse_closure_expression( let block_id = working_set.add_block(Arc::new(output)); - Expression { - expr: Expr::Closure(block_id), - span, - ty: Type::Closure, - custom_completion: None, - } + Expression::new(working_set, Expr::Closure(block_id), span, Type::Closure) } pub fn parse_value( @@ -4545,44 +4439,29 @@ pub fn parse_value( if bytes.is_empty() { working_set.error(ParseError::IncompleteParser(span)); - return garbage(span); + return garbage(working_set, span); } // Check for reserved keyword values match bytes { b"true" => { if matches!(shape, SyntaxShape::Boolean) || matches!(shape, SyntaxShape::Any) { - return Expression { - expr: Expr::Bool(true), - span, - ty: Type::Bool, - custom_completion: None, - }; + return Expression::new(working_set, Expr::Bool(true), span, Type::Bool); } else { working_set.error(ParseError::Expected("non-boolean value", span)); - return Expression::garbage(span); + return Expression::garbage(working_set, span); } } b"false" => { if matches!(shape, SyntaxShape::Boolean) || matches!(shape, SyntaxShape::Any) { - return Expression { - expr: Expr::Bool(false), - span, - ty: Type::Bool, - custom_completion: None, - }; + return Expression::new(working_set, Expr::Bool(false), span, Type::Bool); } else { working_set.error(ParseError::Expected("non-boolean value", span)); - return Expression::garbage(span); + return Expression::garbage(working_set, span); } } b"null" => { - return Expression { - expr: Expr::Nothing, - span, - ty: Type::Nothing, - custom_completion: None, - }; + return Expression::new(working_set, Expr::Nothing, span, Type::Nothing); } b"-inf" | b"inf" | b"NaN" => { return parse_float(working_set, span); @@ -4604,7 +4483,7 @@ pub fn parse_value( | SyntaxShape::GlobPattern => {} _ => { working_set.error(ParseError::Expected("non-[] value", span)); - return Expression::garbage(span); + return Expression::garbage(working_set, span); } }, b'r' if bytes.len() > 1 && bytes[1] == b'#' => { @@ -4637,7 +4516,7 @@ pub fn parse_value( } else { working_set.error(ParseError::Expected("signature", span)); - Expression::garbage(span) + Expression::garbage(working_set, span) } } SyntaxShape::List(elem) => { @@ -4646,7 +4525,7 @@ pub fn parse_value( } else { working_set.error(ParseError::Expected("list", span)); - Expression::garbage(span) + Expression::garbage(working_set, span) } } SyntaxShape::Table(_) => { @@ -4655,23 +4534,18 @@ pub fn parse_value( } else { working_set.error(ParseError::Expected("table", span)); - Expression::garbage(span) + Expression::garbage(working_set, span) } } SyntaxShape::CellPath => parse_simple_cell_path(working_set, span), SyntaxShape::Boolean => { // Redundant, though we catch bad boolean parses here if bytes == b"true" || bytes == b"false" { - Expression { - expr: Expr::Bool(true), - span, - ty: Type::Bool, - custom_completion: None, - } + Expression::new(working_set, Expr::Bool(true), span, Type::Bool) } else { working_set.error(ParseError::Expected("bool", span)); - Expression::garbage(span) + Expression::garbage(working_set, span) } } @@ -4680,7 +4554,7 @@ pub fn parse_value( SyntaxShape::Block | SyntaxShape::Closure(..) | SyntaxShape::Record(_) => { working_set.error(ParseError::Expected("block, closure or record", span)); - Expression::garbage(span) + Expression::garbage(working_set, span) } SyntaxShape::Any => { @@ -4721,7 +4595,7 @@ pub fn parse_value( } } working_set.error(ParseError::Expected("any shape", span)); - garbage(span) + garbage(working_set, span) } } x => { @@ -4729,7 +4603,7 @@ pub fn parse_value( x.to_type().to_string(), span, )); - garbage(span) + garbage(working_set, span) } } } @@ -4783,7 +4657,7 @@ pub fn parse_operator(working_set: &mut StateWorkingSet, span: Span) -> Expressi "Use '**' for exponentiation or 'bit-xor' for bitwise XOR.", span, )); - return garbage(span); + return garbage(working_set, span); } equality @ (b"is" | b"===") => { working_set.error(ParseError::UnknownOperator( @@ -4795,7 +4669,7 @@ pub fn parse_operator(working_set: &mut StateWorkingSet, span: Span) -> Expressi "Did you mean '=='?", span, )); - return garbage(span); + return garbage(working_set, span); } b"contains" => { working_set.error(ParseError::UnknownOperator( @@ -4803,7 +4677,7 @@ pub fn parse_operator(working_set: &mut StateWorkingSet, span: Span) -> Expressi "Did you mean '$string =~ $pattern' or '$element in $container'?", span, )); - return garbage(span); + return garbage(working_set, span); } b"%" => { working_set.error(ParseError::UnknownOperator( @@ -4811,7 +4685,7 @@ pub fn parse_operator(working_set: &mut StateWorkingSet, span: Span) -> Expressi "Did you mean 'mod'?", span, )); - return garbage(span); + return garbage(working_set, span); } b"&" => { working_set.error(ParseError::UnknownOperator( @@ -4819,7 +4693,7 @@ pub fn parse_operator(working_set: &mut StateWorkingSet, span: Span) -> Expressi "Did you mean 'bit-and'?", span, )); - return garbage(span); + return garbage(working_set, span); } b"<<" => { working_set.error(ParseError::UnknownOperator( @@ -4827,7 +4701,7 @@ pub fn parse_operator(working_set: &mut StateWorkingSet, span: Span) -> Expressi "Did you mean 'bit-shl'?", span, )); - return garbage(span); + return garbage(working_set, span); } b">>" => { working_set.error(ParseError::UnknownOperator( @@ -4835,7 +4709,7 @@ pub fn parse_operator(working_set: &mut StateWorkingSet, span: Span) -> Expressi "Did you mean 'bit-shr'?", span, )); - return garbage(span); + return garbage(working_set, span); } bits @ (b"bits-and" | b"bits-xor" | b"bits-or" | b"bits-shl" | b"bits-shr") => { working_set.error(ParseError::UnknownOperator( @@ -4857,20 +4731,15 @@ pub fn parse_operator(working_set: &mut StateWorkingSet, span: Span) -> Expressi }, span, )); - return garbage(span); + return garbage(working_set, span); } _ => { working_set.error(ParseError::Expected("operator", span)); - return garbage(span); + return garbage(working_set, span); } }; - Expression { - expr: Expr::Operator(operator), - span, - ty: Type::Any, - custom_completion: None, - } + Expression::new(working_set, Expr::Operator(operator), span, Type::Any) } pub fn parse_math_expression( @@ -4908,7 +4777,7 @@ pub fn parse_math_expression( "expression", Span::new(spans[0].end, spans[0].end), )); - return garbage(spans[0]); + return garbage(working_set, spans[0]); } } else if first_span == b"not" { not_start_spans.push(spans[idx].start); @@ -4929,19 +4798,25 @@ pub fn parse_math_expression( "expression", Span::new(spans[idx - 1].end, spans[idx - 1].end), )); - return garbage(spans[idx - 1]); + return garbage(working_set, spans[idx - 1]); } } let mut lhs = parse_value(working_set, spans[idx], &SyntaxShape::Any); for not_start_span in not_start_spans.iter().rev() { - lhs = Expression { - expr: Expr::UnaryNot(Box::new(lhs)), - span: Span::new(*not_start_span, spans[idx].end), - ty: Type::Bool, - custom_completion: None, - }; + // lhs = Expression { + // expr: Expr::UnaryNot(Box::new(lhs)), + // span: Span::new(*not_start_span, spans[idx].end), + // ty: Type::Bool, + // custom_completion: None, + // }; + lhs = Expression::new( + working_set, + Expr::UnaryNot(Box::new(lhs)), + Span::new(*not_start_span, spans[idx].end), + Type::Bool, + ); } not_start_spans.clear(); @@ -4967,8 +4842,8 @@ pub fn parse_math_expression( // Handle broken math expr `1 +` etc working_set.error(ParseError::IncompleteMathExpression(spans[idx - 1])); - expr_stack.push(Expression::garbage(spans[idx - 1])); - expr_stack.push(Expression::garbage(spans[idx - 1])); + expr_stack.push(Expression::garbage(working_set, spans[idx - 1])); + expr_stack.push(Expression::garbage(working_set, spans[idx - 1])); break; } @@ -5000,18 +4875,24 @@ pub fn parse_math_expression( "expression", Span::new(spans[idx - 1].end, spans[idx - 1].end), )); - return garbage(spans[idx - 1]); + return garbage(working_set, spans[idx - 1]); } } let mut rhs = parse_value(working_set, spans[idx], &SyntaxShape::Any); for not_start_span in not_start_spans.iter().rev() { - rhs = Expression { - expr: Expr::UnaryNot(Box::new(rhs)), - span: Span::new(*not_start_span, spans[idx].end), - ty: Type::Bool, - custom_completion: None, - }; + // rhs = Expression { + // expr: Expr::UnaryNot(Box::new(rhs)), + // span: Span::new(*not_start_span, spans[idx].end), + // ty: Type::Bool, + // custom_completion: None, + // }; + rhs = Expression::new( + working_set, + Expr::UnaryNot(Box::new(rhs)), + Span::new(*not_start_span, spans[idx].end), + Type::Bool, + ); } not_start_spans.clear(); @@ -5047,12 +4928,12 @@ pub fn parse_math_expression( } let op_span = Span::append(lhs.span, rhs.span); - expr_stack.push(Expression { - expr: Expr::BinaryOp(Box::new(lhs), Box::new(op), Box::new(rhs)), - span: op_span, - ty: result_ty, - custom_completion: None, - }); + expr_stack.push(Expression::new( + working_set, + Expr::BinaryOp(Box::new(lhs), Box::new(op), Box::new(rhs)), + op_span, + result_ty, + )); } expr_stack.push(op); expr_stack.push(rhs); @@ -5083,12 +4964,12 @@ pub fn parse_math_expression( } let binary_op_span = Span::append(lhs.span, rhs.span); - expr_stack.push(Expression { - expr: Expr::BinaryOp(Box::new(lhs), Box::new(op), Box::new(rhs)), - span: binary_op_span, - ty: result_ty, - custom_completion: None, - }); + expr_stack.push(Expression::new( + working_set, + Expr::BinaryOp(Box::new(lhs), Box::new(op), Box::new(rhs)), + binary_op_span, + result_ty, + )); } expr_stack @@ -5131,12 +5012,12 @@ pub fn parse_expression(working_set: &mut StateWorkingSet, spans: &[Span]) -> Ex parse_string_strict(working_set, rhs_span) } } else { - Expression { - expr: Expr::String(String::new()), - span: Span::unknown(), - ty: Type::Nothing, - custom_completion: None, - } + Expression::new( + working_set, + Expr::String(String::new()), + Span::unknown(), + Type::Nothing, + ) }; if starting_error_count == working_set.parse_errors.len() { @@ -5153,7 +5034,7 @@ pub fn parse_expression(working_set: &mut StateWorkingSet, spans: &[Span]) -> Ex if pos == spans.len() { working_set.error(ParseError::UnknownCommand(spans[0])); - return garbage(Span::concat(spans)); + return garbage(working_set, Span::concat(spans)); } let output = if is_math_expression_like(working_set, spans[pos]) { @@ -5246,18 +5127,18 @@ pub fn parse_expression(working_set: &mut StateWorkingSet, spans: &[Span]) -> Ex } let arguments = vec![ - Argument::Positional(Expression { - expr: Expr::Record(env_vars), - span: Span::concat(&spans[..pos]), - ty: Type::Any, - custom_completion: None, - }), - Argument::Positional(Expression { - expr: Expr::Closure(block_id), - span: Span::concat(&spans[pos..]), - ty: Type::Closure, - custom_completion: None, - }), + Argument::Positional(Expression::new( + working_set, + Expr::Record(env_vars), + Span::concat(&spans[..pos]), + Type::Any, + )), + Argument::Positional(Expression::new( + working_set, + Expr::Closure(block_id), + Span::concat(&spans[pos..]), + Type::Closure, + )), ]; let expr = Expr::Call(Box::new(Call { @@ -5267,12 +5148,7 @@ pub fn parse_expression(working_set: &mut StateWorkingSet, spans: &[Span]) -> Ex parser_info: HashMap::new(), })); - Expression { - expr, - custom_completion: None, - span: Span::concat(spans), - ty, - } + Expression::new(working_set, expr, Span::concat(spans), ty) } else { output } @@ -5347,7 +5223,7 @@ pub fn parse_builtin_commands( b"overlay" => { if let Some(redirection) = lite_command.redirection.as_ref() { working_set.error(redirecting_builtin_error("overlay", redirection)); - return garbage_pipeline(&lite_command.parts); + return garbage_pipeline(working_set, &lite_command.parts); } parse_keyword(working_set, lite_command) } @@ -5367,7 +5243,7 @@ pub fn parse_builtin_commands( { if let Some(redirection) = lite_command.redirection.as_ref() { working_set.error(redirecting_builtin_error("plugin use", redirection)); - return garbage_pipeline(&lite_command.parts); + return garbage_pipeline(working_set, &lite_command.parts); } parse_keyword(working_set, lite_command) } @@ -5391,7 +5267,7 @@ pub fn parse_record(working_set: &mut StateWorkingSet, span: Span) -> Expression start += 1; } else { working_set.error(ParseError::Expected("{", Span::new(start, start + 1))); - return garbage(span); + return garbage(working_set, span); } if bytes.ends_with(b"}") { @@ -5456,8 +5332,8 @@ pub fn parse_record(working_set: &mut StateWorkingSet, span: Span) -> Expression Span::new(curr_span.end, curr_span.end), )); output.push(RecordItem::Pair( - garbage(curr_span), - garbage(Span::new(curr_span.end, curr_span.end)), + garbage(working_set, curr_span), + garbage(working_set, Span::new(curr_span.end, curr_span.end)), )); break; } @@ -5471,10 +5347,10 @@ pub fn parse_record(working_set: &mut StateWorkingSet, span: Span) -> Expression )); output.push(RecordItem::Pair( field, - garbage(Span::new( - colon_span.start, - tokens[tokens.len() - 1].span.end, - )), + garbage( + working_set, + Span::new(colon_span.start, tokens[tokens.len() - 1].span.end), + ), )); break; } @@ -5484,8 +5360,11 @@ pub fn parse_record(working_set: &mut StateWorkingSet, span: Span) -> Expression Span::new(colon_span.end, colon_span.end), )); output.push(RecordItem::Pair( - garbage(Span::new(curr_span.start, colon_span.end)), - garbage(Span::new(colon_span.end, tokens[tokens.len() - 1].span.end)), + garbage(working_set, Span::new(curr_span.start, colon_span.end)), + garbage( + working_set, + Span::new(colon_span.end, tokens[tokens.len() - 1].span.end), + ), )); break; } @@ -5505,16 +5384,16 @@ pub fn parse_record(working_set: &mut StateWorkingSet, span: Span) -> Expression } } - Expression { - expr: Expr::Record(output), + Expression::new( + working_set, + Expr::Record(output), span, - ty: (if let Some(fields) = field_types { + if let Some(fields) = field_types { Type::Record(fields.into()) } else { Type::Any - }), - custom_completion: None, - } + }, + ) } fn parse_redirection_target( @@ -6250,12 +6129,12 @@ fn wrap_expr_with_collect(working_set: &mut StateWorkingSet, expr: &Expression) let block_id = working_set.add_block(Arc::new(block)); - output.push(Argument::Positional(Expression { - expr: Expr::Closure(block_id), + output.push(Argument::Positional(Expression::new( + working_set, + Expr::Closure(block_id), span, - ty: Type::Any, - custom_completion: None, - })); + Type::Any, + ))); output.push(Argument::Named(( Spanned { @@ -6269,19 +6148,19 @@ fn wrap_expr_with_collect(working_set: &mut StateWorkingSet, expr: &Expression) // The containing, synthetic call to `collect`. // We don't want to have a real span as it will confuse flattening // The args are where we'll get the real info - Expression { - expr: Expr::Call(Box::new(Call { + Expression::new( + working_set, + Expr::Call(Box::new(Call { head: Span::new(0, 0), arguments: output, decl_id, parser_info: HashMap::new(), })), span, - ty: Type::Any, - custom_completion: None, - } + Type::Any, + ) } else { - Expression::garbage(span) + Expression::garbage(working_set, span) } } diff --git a/crates/nu-parser/src/type_check.rs b/crates/nu-parser/src/type_check.rs index 14c88825db..1c76afb621 100644 --- a/crates/nu-parser/src/type_check.rs +++ b/crates/nu-parser/src/type_check.rs @@ -68,7 +68,7 @@ pub fn type_compatible(lhs: &Type, rhs: &Type) -> bool { } pub fn math_result_type( - _working_set: &StateWorkingSet, + working_set: &mut StateWorkingSet, lhs: &mut Expression, op: &mut Expression, rhs: &mut Expression, @@ -104,7 +104,7 @@ pub fn math_result_type( | Type::Filesize, _, ) => { - *op = Expression::garbage(op.span); + *op = Expression::garbage(working_set, op.span); ( Type::Any, Some(ParseError::UnsupportedOperationRHS( @@ -118,7 +118,7 @@ pub fn math_result_type( ) } _ => { - *op = Expression::garbage(op.span); + *op = Expression::garbage(working_set, op.span); ( Type::Any, Some(ParseError::UnsupportedOperationLHS( @@ -130,7 +130,7 @@ pub fn math_result_type( ) } }, - Operator::Math(Math::Append) => check_append(lhs, rhs, op), + Operator::Math(Math::Append) => check_append(working_set, lhs, rhs, op), Operator::Math(Math::Minus) => match (&lhs.ty, &rhs.ty) { (Type::Int, Type::Int) => (Type::Int, None), (Type::Float, Type::Int) => (Type::Float, None), @@ -152,7 +152,7 @@ pub fn math_result_type( (Type::Any, _) => (Type::Any, None), (_, Type::Any) => (Type::Any, None), (Type::Int | Type::Float | Type::Date | Type::Duration | Type::Filesize, _) => { - *op = Expression::garbage(op.span); + *op = Expression::garbage(working_set, op.span); ( Type::Any, Some(ParseError::UnsupportedOperationRHS( @@ -166,7 +166,7 @@ pub fn math_result_type( ) } _ => { - *op = Expression::garbage(op.span); + *op = Expression::garbage(working_set, op.span); ( Type::Any, Some(ParseError::UnsupportedOperationLHS( @@ -209,7 +209,7 @@ pub fn math_result_type( | (Type::Duration, _) | (Type::Filesize, _) | (Type::List(_), _) => { - *op = Expression::garbage(op.span); + *op = Expression::garbage(working_set, op.span); ( Type::Any, Some(ParseError::UnsupportedOperationRHS( @@ -223,7 +223,7 @@ pub fn math_result_type( ) } _ => { - *op = Expression::garbage(op.span); + *op = Expression::garbage(working_set, op.span); ( Type::Any, Some(ParseError::UnsupportedOperationLHS( @@ -252,7 +252,7 @@ pub fn math_result_type( (Type::Any, _) => (Type::Any, None), (_, Type::Any) => (Type::Any, None), (Type::Int | Type::Float, _) => { - *op = Expression::garbage(op.span); + *op = Expression::garbage(working_set, op.span); ( Type::Any, Some(ParseError::UnsupportedOperationRHS( @@ -266,7 +266,7 @@ pub fn math_result_type( ) } _ => { - *op = Expression::garbage(op.span); + *op = Expression::garbage(working_set, op.span); ( Type::Any, Some(ParseError::UnsupportedOperationLHS( @@ -302,7 +302,7 @@ pub fn math_result_type( (Type::Any, _) => (Type::Any, None), (_, Type::Any) => (Type::Any, None), (Type::Int | Type::Float | Type::Filesize | Type::Duration, _) => { - *op = Expression::garbage(op.span); + *op = Expression::garbage(working_set, op.span); ( Type::Any, Some(ParseError::UnsupportedOperationRHS( @@ -316,7 +316,7 @@ pub fn math_result_type( ) } _ => { - *op = Expression::garbage(op.span); + *op = Expression::garbage(working_set, op.span); ( Type::Any, Some(ParseError::UnsupportedOperationLHS( @@ -348,7 +348,7 @@ pub fn math_result_type( (Type::Any, _) => (Type::Any, None), (_, Type::Any) => (Type::Any, None), (Type::Int | Type::Float | Type::Filesize | Type::Duration, _) => { - *op = Expression::garbage(op.span); + *op = Expression::garbage(working_set, op.span); ( Type::Any, Some(ParseError::UnsupportedOperationRHS( @@ -362,7 +362,7 @@ pub fn math_result_type( ) } _ => { - *op = Expression::garbage(op.span); + *op = Expression::garbage(working_set, op.span); ( Type::Any, Some(ParseError::UnsupportedOperationLHS( @@ -390,7 +390,7 @@ pub fn math_result_type( // definitions. As soon as that syntax is added this should be removed (a, b) if a == b => (Type::Bool, None), (Type::Bool, _) => { - *op = Expression::garbage(op.span); + *op = Expression::garbage(working_set, op.span); ( Type::Any, Some(ParseError::UnsupportedOperationRHS( @@ -404,7 +404,7 @@ pub fn math_result_type( ) } _ => { - *op = Expression::garbage(op.span); + *op = Expression::garbage(working_set, op.span); ( Type::Any, Some(ParseError::UnsupportedOperationLHS( @@ -441,7 +441,7 @@ pub fn math_result_type( (Type::Any, _) => (Type::Bool, None), (_, Type::Any) => (Type::Bool, None), (Type::Int | Type::Float | Type::Duration | Type::Filesize, _) => { - *op = Expression::garbage(op.span); + *op = Expression::garbage(working_set, op.span); ( Type::Any, Some(ParseError::UnsupportedOperationRHS( @@ -455,7 +455,7 @@ pub fn math_result_type( ) } _ => { - *op = Expression::garbage(op.span); + *op = Expression::garbage(working_set, op.span); ( Type::Any, Some(ParseError::UnsupportedOperationLHS( @@ -491,7 +491,7 @@ pub fn math_result_type( (Type::Any, _) => (Type::Bool, None), (_, Type::Any) => (Type::Bool, None), (Type::Int | Type::Float | Type::Duration | Type::Filesize, _) => { - *op = Expression::garbage(op.span); + *op = Expression::garbage(working_set, op.span); ( Type::Any, Some(ParseError::UnsupportedOperationRHS( @@ -505,7 +505,7 @@ pub fn math_result_type( ) } _ => { - *op = Expression::garbage(op.span); + *op = Expression::garbage(working_set, op.span); ( Type::Any, Some(ParseError::UnsupportedOperationLHS( @@ -541,7 +541,7 @@ pub fn math_result_type( (Type::Nothing, _) => (Type::Nothing, None), (_, Type::Nothing) => (Type::Nothing, None), (Type::Int | Type::Float | Type::Duration | Type::Filesize, _) => { - *op = Expression::garbage(op.span); + *op = Expression::garbage(working_set, op.span); ( Type::Any, Some(ParseError::UnsupportedOperationRHS( @@ -555,7 +555,7 @@ pub fn math_result_type( ) } _ => { - *op = Expression::garbage(op.span); + *op = Expression::garbage(working_set, op.span); ( Type::Any, Some(ParseError::UnsupportedOperationLHS( @@ -591,7 +591,7 @@ pub fn math_result_type( (Type::Nothing, _) => (Type::Nothing, None), (_, Type::Nothing) => (Type::Nothing, None), (Type::Int | Type::Float | Type::Duration | Type::Filesize, _) => { - *op = Expression::garbage(op.span); + *op = Expression::garbage(working_set, op.span); ( Type::Any, Some(ParseError::UnsupportedOperationRHS( @@ -605,7 +605,7 @@ pub fn math_result_type( ) } _ => { - *op = Expression::garbage(op.span); + *op = Expression::garbage(working_set, op.span); ( Type::Any, Some(ParseError::UnsupportedOperationLHS( @@ -638,7 +638,7 @@ pub fn math_result_type( (Type::Custom(a), _) => (Type::Custom(a.clone()), None), (Type::String, _) => { - *op = Expression::garbage(op.span); + *op = Expression::garbage(working_set, op.span); ( Type::Any, Some(ParseError::UnsupportedOperationRHS( @@ -652,7 +652,7 @@ pub fn math_result_type( ) } _ => { - *op = Expression::garbage(op.span); + *op = Expression::garbage(working_set, op.span); ( Type::Any, Some(ParseError::UnsupportedOperationLHS( @@ -673,7 +673,7 @@ pub fn math_result_type( (Type::Custom(a), _) => (Type::Custom(a.clone()), None), (Type::String, _) => { - *op = Expression::garbage(op.span); + *op = Expression::garbage(working_set, op.span); ( Type::Any, Some(ParseError::UnsupportedOperationRHS( @@ -687,7 +687,7 @@ pub fn math_result_type( ) } _ => { - *op = Expression::garbage(op.span); + *op = Expression::garbage(working_set, op.span); ( Type::Any, Some(ParseError::UnsupportedOperationLHS( @@ -708,7 +708,7 @@ pub fn math_result_type( (Type::Custom(a), _) => (Type::Custom(a.clone()), None), (Type::String, _) => { - *op = Expression::garbage(op.span); + *op = Expression::garbage(working_set, op.span); ( Type::Any, Some(ParseError::UnsupportedOperationRHS( @@ -722,7 +722,7 @@ pub fn math_result_type( ) } _ => { - *op = Expression::garbage(op.span); + *op = Expression::garbage(working_set, op.span); ( Type::Any, Some(ParseError::UnsupportedOperationLHS( @@ -743,7 +743,7 @@ pub fn math_result_type( (Type::Custom(a), _) => (Type::Custom(a.clone()), None), (Type::String, _) => { - *op = Expression::garbage(op.span); + *op = Expression::garbage(working_set, op.span); ( Type::Any, Some(ParseError::UnsupportedOperationRHS( @@ -757,7 +757,7 @@ pub fn math_result_type( ) } _ => { - *op = Expression::garbage(op.span); + *op = Expression::garbage(working_set, op.span); ( Type::Any, Some(ParseError::UnsupportedOperationLHS( @@ -781,7 +781,7 @@ pub fn math_result_type( (Type::Any, _) => (Type::Bool, None), (_, Type::Any) => (Type::Bool, None), (Type::Int | Type::Float | Type::String, _) => { - *op = Expression::garbage(op.span); + *op = Expression::garbage(working_set, op.span); ( Type::Any, Some(ParseError::UnsupportedOperationRHS( @@ -795,7 +795,7 @@ pub fn math_result_type( ) } _ => { - *op = Expression::garbage(op.span); + *op = Expression::garbage(working_set, op.span); ( Type::Any, Some(ParseError::UnsupportedOperationLHS( @@ -819,7 +819,7 @@ pub fn math_result_type( (Type::Any, _) => (Type::Bool, None), (_, Type::Any) => (Type::Bool, None), (Type::Int | Type::Float | Type::String, _) => { - *op = Expression::garbage(op.span); + *op = Expression::garbage(working_set, op.span); ( Type::Any, Some(ParseError::UnsupportedOperationRHS( @@ -833,7 +833,7 @@ pub fn math_result_type( ) } _ => { - *op = Expression::garbage(op.span); + *op = Expression::garbage(working_set, op.span); ( Type::Any, Some(ParseError::UnsupportedOperationLHS( @@ -855,7 +855,7 @@ pub fn math_result_type( (Type::Any, _) => (Type::Any, None), (_, Type::Any) => (Type::Any, None), (Type::Int, _) => { - *op = Expression::garbage(op.span); + *op = Expression::garbage(working_set, op.span); ( Type::Any, Some(ParseError::UnsupportedOperationRHS( @@ -869,7 +869,7 @@ pub fn math_result_type( ) } _ => { - *op = Expression::garbage(op.span); + *op = Expression::garbage(working_set, op.span); ( Type::Any, Some(ParseError::UnsupportedOperationLHS( @@ -881,7 +881,9 @@ pub fn math_result_type( ) } }, - Operator::Assignment(Assignment::AppendAssign) => check_append(lhs, rhs, op), + Operator::Assignment(Assignment::AppendAssign) => { + check_append(working_set, lhs, rhs, op) + } Operator::Assignment(_) => match (&lhs.ty, &rhs.ty) { (x, y) if x == y => (Type::Nothing, None), (Type::Any, _) => (Type::Nothing, None), @@ -894,7 +896,7 @@ pub fn math_result_type( }, }, _ => { - *op = Expression::garbage(op.span); + *op = Expression::garbage(working_set, op.span); ( Type::Any, @@ -1026,6 +1028,7 @@ pub fn check_block_input_output(working_set: &StateWorkingSet, block: &Block) -> } fn check_append( + working_set: &mut StateWorkingSet, lhs: &Expression, rhs: &Expression, op: &mut Expression, @@ -1050,7 +1053,7 @@ fn check_append( (Type::Binary, Type::Binary) => (Type::Binary, None), (Type::Any, _) | (_, Type::Any) => (Type::Any, None), (Type::Table(_) | Type::String | Type::Binary, _) => { - *op = Expression::garbage(op.span); + *op = Expression::garbage(working_set, op.span); ( Type::Any, Some(ParseError::UnsupportedOperationRHS( @@ -1064,7 +1067,7 @@ fn check_append( ) } _ => { - *op = Expression::garbage(op.span); + *op = Expression::garbage(working_set, op.span); ( Type::Any, Some(ParseError::UnsupportedOperationLHS( diff --git a/crates/nu-protocol/src/ast/call.rs b/crates/nu-protocol/src/ast/call.rs index 9aaf17d5db..6e8cc64a05 100644 --- a/crates/nu-protocol/src/ast/call.rs +++ b/crates/nu-protocol/src/ast/call.rs @@ -338,9 +338,13 @@ impl Call { #[cfg(test)] mod test { use super::*; + use crate::engine::EngineState; #[test] fn argument_span_named() { + let engine_state = EngineState::new(); + let mut working_set = StateWorkingSet::new(&engine_state); + let named = Spanned { item: "named".to_string(), span: Span::new(2, 3), @@ -349,7 +353,7 @@ mod test { item: "short".to_string(), span: Span::new(5, 7), }; - let expr = Expression::garbage(Span::new(11, 13)); + let expr = Expression::garbage(&mut working_set, Span::new(11, 13)); let arg = Argument::Named((named.clone(), None, None)); @@ -370,8 +374,11 @@ mod test { #[test] fn argument_span_positional() { + let engine_state = EngineState::new(); + let mut working_set = StateWorkingSet::new(&engine_state); + let span = Span::new(2, 3); - let expr = Expression::garbage(span); + let expr = Expression::garbage(&mut working_set, span); let arg = Argument::Positional(expr); assert_eq!(span, arg.span()); @@ -379,8 +386,11 @@ mod test { #[test] fn argument_span_unknown() { + let engine_state = EngineState::new(); + let mut working_set = StateWorkingSet::new(&engine_state); + let span = Span::new(2, 3); - let expr = Expression::garbage(span); + let expr = Expression::garbage(&mut working_set, span); let arg = Argument::Unknown(expr); assert_eq!(span, arg.span()); @@ -388,9 +398,12 @@ mod test { #[test] fn call_arguments_span() { + let engine_state = EngineState::new(); + let mut working_set = StateWorkingSet::new(&engine_state); + let mut call = Call::new(Span::new(0, 1)); - call.add_positional(Expression::garbage(Span::new(2, 3))); - call.add_positional(Expression::garbage(Span::new(5, 7))); + call.add_positional(Expression::garbage(&mut working_set, Span::new(2, 3))); + call.add_positional(Expression::garbage(&mut working_set, Span::new(5, 7))); assert_eq!(Span::new(2, 7), call.arguments_span()); } diff --git a/crates/nu-protocol/src/ast/expression.rs b/crates/nu-protocol/src/ast/expression.rs index 8fdbc8567c..832bc1f438 100644 --- a/crates/nu-protocol/src/ast/expression.rs +++ b/crates/nu-protocol/src/ast/expression.rs @@ -1,7 +1,7 @@ use crate::{ ast::{Argument, Block, Expr, ExternalArgument, ImportPattern, MatchPattern, RecordItem}, - engine::StateWorkingSet, - BlockId, DeclId, Signature, Span, Type, VarId, IN_VARIABLE_ID, + engine::{EngineState, StateWorkingSet}, + BlockId, DeclId, Signature, Span, SpanId, Type, VarId, IN_VARIABLE_ID, }; use serde::{Deserialize, Serialize}; use std::sync::Arc; @@ -10,15 +10,18 @@ use std::sync::Arc; pub struct Expression { pub expr: Expr, pub span: Span, + pub span_id: SpanId, pub ty: Type, pub custom_completion: Option, } impl Expression { - pub fn garbage(span: Span) -> Expression { + pub fn garbage(working_set: &mut StateWorkingSet, span: Span) -> Expression { + let span_id = working_set.add_span(span); Expression { expr: Expr::Garbage, span, + span_id, ty: Type::Any, custom_completion: None, } @@ -471,4 +474,49 @@ impl Expression { Expr::VarDecl(_) => {} } } + + pub fn new(working_set: &mut StateWorkingSet, expr: Expr, span: Span, ty: Type) -> Expression { + let span_id = working_set.add_span(span); + Expression { + expr, + span, + span_id, + ty, + custom_completion: None, + } + } + + pub fn new_existing(expr: Expr, span: Span, span_id: SpanId, ty: Type) -> Expression { + Expression { + expr, + span, + span_id, + ty, + custom_completion: None, + } + } + + pub fn new_unknown(expr: Expr, span: Span, ty: Type) -> Expression { + Expression { + expr, + span, + span_id: SpanId(0), + ty, + custom_completion: None, + } + } + + pub fn with_span_id(self, span_id: SpanId) -> Expression { + Expression { + expr: self.expr, + span: self.span, + span_id, + ty: self.ty, + custom_completion: self.custom_completion, + } + } + + pub fn span(&self, engine_state: &EngineState) -> Span { + engine_state.get_span(self.span_id) + } } diff --git a/crates/nu-protocol/src/engine/engine_state.rs b/crates/nu-protocol/src/engine/engine_state.rs index 710ca77d4c..e81d3360ab 100644 --- a/crates/nu-protocol/src/engine/engine_state.rs +++ b/crates/nu-protocol/src/engine/engine_state.rs @@ -8,7 +8,7 @@ use crate::{ }, eval_const::create_nu_constant, BlockId, Category, Config, DeclId, FileId, HistoryConfig, Module, ModuleId, OverlayId, - ShellError, Signature, Span, Type, Value, VarId, VirtualPathId, + ShellError, Signature, Span, SpanId, Type, Value, VarId, VirtualPathId, }; use fancy_regex::Regex; use lru::LruCache; @@ -81,6 +81,7 @@ pub struct EngineState { // especially long, so it helps pub(super) blocks: Arc>>, pub(super) modules: Arc>>, + pub spans: Vec, usage: Usage, pub scope: ScopeFrame, pub ctrlc: Option>, @@ -115,6 +116,9 @@ pub const IN_VARIABLE_ID: usize = 1; pub const ENV_VARIABLE_ID: usize = 2; // NOTE: If you add more to this list, make sure to update the > checks based on the last in the list +// The first span is unknown span +pub const UNKNOWN_SPAN_ID: SpanId = SpanId(0); + impl EngineState { pub fn new() -> Self { Self { @@ -132,6 +136,7 @@ impl EngineState { modules: Arc::new(vec![Arc::new(Module::new( DEFAULT_OVERLAY_NAME.as_bytes().to_vec(), ))]), + spans: vec![Span::unknown()], usage: Usage::new(), // make sure we have some default overlay: scope: ScopeFrame::with_empty_overlay( @@ -184,6 +189,7 @@ impl EngineState { self.files.extend(delta.files); self.virtual_paths.extend(delta.virtual_paths); self.vars.extend(delta.vars); + self.spans.extend(delta.spans); self.usage.merge_with(delta.usage); // Avoid potentially cloning the Arcs if we aren't adding anything @@ -565,6 +571,9 @@ impl EngineState { self.modules.len() } + pub fn num_spans(&self) -> usize { + self.spans.len() + } pub fn print_vars(&self) { for var in self.vars.iter().enumerate() { println!("var{}: {:?}", var.0, var.1); @@ -1019,6 +1028,25 @@ impl EngineState { ))); } } + + /// Add new span and return its ID + pub fn add_span(&mut self, span: Span) -> SpanId { + self.spans.push(span); + SpanId(self.num_spans() - 1) + } + + /// Get existing span + pub fn get_span(&self, span_id: SpanId) -> Span { + *self + .spans + .get(span_id.0) + .expect("internal error: missing span") + } + + /// Find ID of a span (should be avoided if possible) + pub fn find_span_id(&self, span: Span) -> Option { + self.spans.iter().position(|sp| sp == &span).map(SpanId) + } } impl Default for EngineState { diff --git a/crates/nu-protocol/src/engine/state_delta.rs b/crates/nu-protocol/src/engine/state_delta.rs index 1e283bade8..44c1b37386 100644 --- a/crates/nu-protocol/src/engine/state_delta.rs +++ b/crates/nu-protocol/src/engine/state_delta.rs @@ -4,7 +4,7 @@ use crate::{ usage::Usage, CachedFile, Command, EngineState, OverlayFrame, ScopeFrame, Variable, VirtualPath, }, - Module, + Module, Span, }; use std::sync::Arc; @@ -21,6 +21,7 @@ pub struct StateDelta { pub(super) decls: Vec>, // indexed by DeclId pub blocks: Vec>, // indexed by BlockId pub(super) modules: Vec>, // indexed by ModuleId + pub spans: Vec, // indexed by SpanId pub(super) usage: Usage, pub scope: Vec, #[cfg(feature = "plugin")] @@ -45,6 +46,7 @@ impl StateDelta { decls: vec![], blocks: vec![], modules: vec![], + spans: vec![], scope: vec![scope_frame], usage: Usage::new(), #[cfg(feature = "plugin")] diff --git a/crates/nu-protocol/src/engine/state_working_set.rs b/crates/nu-protocol/src/engine/state_working_set.rs index 0fe39682e2..31600b5eb9 100644 --- a/crates/nu-protocol/src/engine/state_working_set.rs +++ b/crates/nu-protocol/src/engine/state_working_set.rs @@ -5,7 +5,7 @@ use crate::{ StateDelta, Variable, VirtualPath, Visibility, }, BlockId, Category, Config, DeclId, FileId, Module, ModuleId, ParseError, ParseWarning, Span, - Type, Value, VarId, VirtualPathId, + SpanId, Type, Value, VarId, VirtualPathId, }; use core::panic; use std::{ @@ -1013,6 +1013,25 @@ impl<'a> StateWorkingSet<'a> { .expect("internal error: missing virtual path") } } + + pub fn add_span(&mut self, span: Span) -> SpanId { + let num_permanent_spans = self.permanent_state.spans.len(); + self.delta.spans.push(span); + SpanId(num_permanent_spans + self.delta.spans.len() - 1) + } + + pub fn get_span(&self, span_id: SpanId) -> Span { + let num_permanent_spans = self.permanent_state.num_spans(); + if span_id.0 < num_permanent_spans { + self.permanent_state.get_span(span_id) + } else { + *self + .delta + .spans + .get(span_id.0 - num_permanent_spans) + .expect("internal error: missing span") + } + } } impl<'a> miette::SourceCode for &StateWorkingSet<'a> { diff --git a/crates/nu-protocol/src/id.rs b/crates/nu-protocol/src/id.rs index dc9978b844..73c4f52e70 100644 --- a/crates/nu-protocol/src/id.rs +++ b/crates/nu-protocol/src/id.rs @@ -1,3 +1,5 @@ +use serde::{Deserialize, Serialize}; + pub type VarId = usize; pub type DeclId = usize; pub type BlockId = usize; @@ -5,3 +7,5 @@ pub type ModuleId = usize; pub type OverlayId = usize; pub type FileId = usize; pub type VirtualPathId = usize; +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] +pub struct SpanId(pub usize); // more robust ID style used in the new parser diff --git a/crates/nuon/src/from.rs b/crates/nuon/src/from.rs index 862b756db7..f9230d6140 100644 --- a/crates/nuon/src/from.rs +++ b/crates/nuon/src/from.rs @@ -56,12 +56,12 @@ pub fn from_nuon(input: &str, span: Option) -> Result { } let expr = if block.pipelines.is_empty() { - Expression { - expr: Expr::Nothing, - span: span.unwrap_or(Span::unknown()), - custom_completion: None, - ty: Type::Nothing, - } + Expression::new( + &mut working_set, + Expr::Nothing, + span.unwrap_or(Span::unknown()), + Type::Nothing, + ) } else { let mut pipeline = Arc::make_mut(&mut block).pipelines.remove(0); @@ -81,12 +81,12 @@ pub fn from_nuon(input: &str, span: Option) -> Result { } if pipeline.elements.is_empty() { - Expression { - expr: Expr::Nothing, - span: span.unwrap_or(Span::unknown()), - custom_completion: None, - ty: Type::Nothing, - } + Expression::new( + &mut working_set, + Expr::Nothing, + span.unwrap_or(Span::unknown()), + Type::Nothing, + ) } else { pipeline.elements.remove(0).expr }