From 2ac990655e2c7604d2417d632eb0170cba4f3f83 Mon Sep 17 00:00:00 2001 From: JT <547158+jntrnr@users.noreply.github.com> Date: Wed, 9 Mar 2022 04:42:19 -0500 Subject: [PATCH] Add support for var decl spans (#4787) --- .../nu-command/src/core_commands/metadata.rs | 30 +++++++----- crates/nu-engine/src/eval.rs | 2 +- crates/nu-parser/src/parser.rs | 48 +++++++++++++------ crates/nu-protocol/src/engine/engine_state.rs | 26 +++++----- crates/nu-protocol/src/lib.rs | 4 +- crates/nu-protocol/src/variable.rs | 16 +++++++ 6 files changed, 85 insertions(+), 41 deletions(-) create mode 100644 crates/nu-protocol/src/variable.rs diff --git a/crates/nu-command/src/core_commands/metadata.rs b/crates/nu-command/src/core_commands/metadata.rs index d84d1a4e8..caacb0b45 100644 --- a/crates/nu-command/src/core_commands/metadata.rs +++ b/crates/nu-command/src/core_commands/metadata.rs @@ -2,8 +2,8 @@ use nu_engine::CallExt; use nu_protocol::ast::{Call, Expr, Expression}; use nu_protocol::engine::{Command, EngineState, Stack}; use nu_protocol::{ - Category, DataSource, Example, IntoPipelineData, PipelineData, PipelineMetadata, Signature, - Span, SyntaxShape, Value, + Category, DataSource, Example, IntoPipelineData, PipelineData, PipelineMetadata, ShellError, + Signature, Span, SyntaxShape, Value, }; #[derive(Clone)] @@ -41,7 +41,6 @@ impl Command for Metadata { match arg { Some(Expression { expr: Expr::FullCellPath(full_cell_path), - span, .. }) => { if full_cell_path.tail.is_empty() { @@ -50,25 +49,30 @@ impl Command for Metadata { expr: Expr::Var(var_id), .. } => { - let origin = stack.get_var_with_origin(*var_id, *span)?; + let variable = engine_state.get_var(*var_id); - Ok(build_metadata_record(&origin, &input.metadata(), head) - .into_pipeline_data()) + Ok(build_metadata_record( + Ok(variable.declaration_span), + &input.metadata(), + head, + ) + .into_pipeline_data()) } _ => { let val: Value = call.req(engine_state, stack, 0)?; - Ok(build_metadata_record(&val, &input.metadata(), head) + Ok(build_metadata_record(val.span(), &input.metadata(), head) .into_pipeline_data()) } } } else { let val: Value = call.req(engine_state, stack, 0)?; - Ok(build_metadata_record(&val, &input.metadata(), head).into_pipeline_data()) + Ok(build_metadata_record(val.span(), &input.metadata(), head) + .into_pipeline_data()) } } Some(_) => { let val: Value = call.req(engine_state, stack, 0)?; - Ok(build_metadata_record(&val, &input.metadata(), head).into_pipeline_data()) + Ok(build_metadata_record(val.span(), &input.metadata(), head).into_pipeline_data()) } None => { let mut cols = vec![]; @@ -113,11 +117,15 @@ impl Command for Metadata { } } -fn build_metadata_record(arg: &Value, metadata: &Option, head: Span) -> Value { +fn build_metadata_record( + span: Result, + metadata: &Option, + head: Span, +) -> Value { let mut cols = vec![]; let mut vals = vec![]; - if let Ok(span) = arg.span() { + if let Ok(span) = span { cols.push("span".into()); vals.push(Value::Record { cols: vec!["start".into(), "end".into()], diff --git a/crates/nu-engine/src/eval.rs b/crates/nu-engine/src/eval.rs index 322ea0cd7..50b679c6f 100644 --- a/crates/nu-engine/src/eval.rs +++ b/crates/nu-engine/src/eval.rs @@ -761,7 +761,7 @@ pub fn create_scope( for var in &frame.vars { let var_name = Value::string(String::from_utf8_lossy(var.0).to_string(), span); - let var_type = Value::string(engine_state.get_var(*var.1).to_string(), span); + let var_type = Value::string(engine_state.get_var(*var.1).ty.to_string(), span); let var_value = if let Ok(val) = stack.get_var(*var.1, span) { val diff --git a/crates/nu-parser/src/parser.rs b/crates/nu-parser/src/parser.rs index b758650f5..8bc27ab6b 100644 --- a/crates/nu-parser/src/parser.rs +++ b/crates/nu-parser/src/parser.rs @@ -1596,7 +1596,7 @@ pub fn parse_variable_expr( Expression { expr: Expr::Var(id), span, - ty: working_set.get_variable(id).clone(), + ty: working_set.get_variable(id).ty.clone(), custom_completion: None, }, None, @@ -2632,7 +2632,11 @@ pub fn parse_var_with_opt_type( let ty = parse_type(working_set, type_bytes); - let id = working_set.add_variable(bytes[0..(bytes.len() - 1)].to_vec(), ty.clone()); + let id = working_set.add_variable( + bytes[0..(bytes.len() - 1)].to_vec(), + spans[*spans_idx - 1], + ty.clone(), + ); ( Expression { @@ -2644,7 +2648,11 @@ pub fn parse_var_with_opt_type( None, ) } else { - let id = working_set.add_variable(bytes[0..(bytes.len() - 1)].to_vec(), Type::Unknown); + let id = working_set.add_variable( + bytes[0..(bytes.len() - 1)].to_vec(), + spans[*spans_idx], + Type::Unknown, + ); ( Expression { expr: Expr::VarDecl(id), @@ -2666,7 +2674,11 @@ pub fn parse_var_with_opt_type( None, ) } else { - let id = working_set.add_variable(bytes, Type::Unknown); + let id = working_set.add_variable( + bytes, + span(&spans[*spans_idx..*spans_idx + 1]), + Type::Unknown, + ); ( Expression { @@ -2702,7 +2714,7 @@ pub fn parse_row_condition( working_set: &mut StateWorkingSet, spans: &[Span], ) -> (Expression, Option) { - let var_id = working_set.add_variable(b"$it".to_vec(), Type::Unknown); + let var_id = working_set.add_variable(b"$it".to_vec(), span(spans), Type::Unknown); let (expression, err) = parse_math_expression(working_set, spans, Some(var_id)); let span = span(spans); @@ -2858,7 +2870,8 @@ pub fn parse_signature_helper( let long = String::from_utf8_lossy(&flags[0][2..]).to_string(); let variable_name = flags[0][2..].to_vec(); - let var_id = working_set.add_variable(variable_name, Type::Unknown); + let var_id = + working_set.add_variable(variable_name, span, Type::Unknown); if flags.len() == 1 { args.push(Arg::Flag(Flag { @@ -2888,8 +2901,11 @@ pub fn parse_signature_helper( let chars: Vec = short_flag.chars().collect(); let long = String::from_utf8_lossy(&flags[0][2..]).to_string(); let variable_name = flags[0][2..].to_vec(); - let var_id = - working_set.add_variable(variable_name, Type::Unknown); + let var_id = working_set.add_variable( + variable_name, + span, + Type::Unknown, + ); if chars.len() == 1 { args.push(Arg::Flag(Flag { @@ -2923,7 +2939,8 @@ pub fn parse_signature_helper( let mut encoded_var_name = vec![0u8; 4]; let len = chars[0].encode_utf8(&mut encoded_var_name).len(); let variable_name = encoded_var_name[0..len].to_vec(); - let var_id = working_set.add_variable(variable_name, Type::Unknown); + let var_id = + working_set.add_variable(variable_name, span, Type::Unknown); args.push(Arg::Flag(Flag { arg: None, @@ -2981,7 +2998,8 @@ pub fn parse_signature_helper( let contents: Vec<_> = contents[..(contents.len() - 1)].into(); let name = String::from_utf8_lossy(&contents).to_string(); - let var_id = working_set.add_variable(contents, Type::Unknown); + let var_id = + working_set.add_variable(contents, span, Type::Unknown); // Positional arg, optional args.push(Arg::Positional( @@ -2998,7 +3016,8 @@ pub fn parse_signature_helper( let name = String::from_utf8_lossy(contents).to_string(); let contents_vec: Vec = contents.to_vec(); - let var_id = working_set.add_variable(contents_vec, Type::Unknown); + let var_id = + working_set.add_variable(contents_vec, span, Type::Unknown); args.push(Arg::RestPositional(PositionalArg { desc: String::new(), @@ -3011,7 +3030,8 @@ pub fn parse_signature_helper( let name = String::from_utf8_lossy(contents).to_string(); let contents_vec = contents.to_vec(); - let var_id = working_set.add_variable(contents_vec, Type::Unknown); + let var_id = + working_set.add_variable(contents_vec, span, Type::Unknown); // Positional arg, required args.push(Arg::Positional( @@ -3072,7 +3092,7 @@ pub fn parse_signature_helper( required, ) => { let var_id = var_id.expect("internal error: all custom parameters must have var_ids"); - let var_type = working_set.get_variable(var_id); + let var_type = &working_set.get_variable(var_id).ty; match var_type { Type::Unknown => { working_set.set_variable_type( @@ -3112,7 +3132,7 @@ pub fn parse_signature_helper( .. }) => { let var_id = var_id.expect("internal error: all custom parameters must have var_ids"); - let var_type = working_set.get_variable(var_id); + let var_type = &working_set.get_variable(var_id).ty; let expression_ty = expression.ty.clone(); let expression_span = expression.span; diff --git a/crates/nu-protocol/src/engine/engine_state.rs b/crates/nu-protocol/src/engine/engine_state.rs index fcb6512ad..85e57f1a2 100644 --- a/crates/nu-protocol/src/engine/engine_state.rs +++ b/crates/nu-protocol/src/engine/engine_state.rs @@ -1,7 +1,7 @@ use super::{Command, Stack}; use crate::{ ast::Block, AliasId, BlockId, DeclId, Example, Overlay, OverlayId, ShellError, Signature, Span, - Type, VarId, + Type, VarId, Variable, }; use core::panic; use std::{ @@ -159,7 +159,7 @@ impl Default for ScopeFrame { pub struct EngineState { files: im::Vector<(String, usize, usize)>, file_contents: im::Vector<(Vec, usize, usize)>, - vars: im::Vector, + vars: im::Vector, decls: im::Vector>, aliases: im::Vector>, blocks: im::Vector, @@ -186,11 +186,11 @@ impl EngineState { files: im::vector![], file_contents: im::vector![], vars: im::vector![ - Type::Unknown, - Type::Unknown, - Type::Unknown, - Type::Unknown, - Type::Unknown + Variable::new(Span::new(0, 0), Type::Unknown), + Variable::new(Span::new(0, 0), Type::Unknown), + Variable::new(Span::new(0, 0), Type::Unknown), + Variable::new(Span::new(0, 0), Type::Unknown), + Variable::new(Span::new(0, 0), Type::Unknown) ], decls: im::vector![], aliases: im::vector![], @@ -481,7 +481,7 @@ impl EngineState { panic!("internal error: span missing in file contents cache") } - pub fn get_var(&self, var_id: VarId) -> &Type { + pub fn get_var(&self, var_id: VarId) -> &Variable { self.vars .get(var_id) .expect("internal error: missing variable") @@ -655,7 +655,7 @@ pub struct StateWorkingSet<'a> { pub struct StateDelta { files: Vec<(String, usize, usize)>, pub(crate) file_contents: Vec<(Vec, usize, usize)>, - vars: Vec, // indexed by VarId + vars: Vec, // indexed by VarId decls: Vec>, // indexed by DeclId aliases: Vec>, // indexed by AliasId pub blocks: Vec, // indexed by BlockId @@ -1136,7 +1136,7 @@ impl<'a> StateWorkingSet<'a> { None } - pub fn add_variable(&mut self, mut name: Vec, ty: Type) -> VarId { + pub fn add_variable(&mut self, mut name: Vec, span: Span, ty: Type) -> VarId { let next_id = self.next_var_id(); // correct name if necessary @@ -1152,7 +1152,7 @@ impl<'a> StateWorkingSet<'a> { last.vars.insert(name, next_id); - self.delta.vars.push(ty); + self.delta.vars.push(Variable::new(span, ty)); next_id } @@ -1185,11 +1185,11 @@ impl<'a> StateWorkingSet<'a> { if var_id < num_permanent_vars { panic!("Internal error: attempted to set into permanent state from working set") } else { - self.delta.vars[var_id - num_permanent_vars] = ty; + self.delta.vars[var_id - num_permanent_vars].ty = ty; } } - pub fn get_variable(&self, var_id: VarId) -> &Type { + pub fn get_variable(&self, var_id: VarId) -> &Variable { let num_permanent_vars = self.permanent_state.num_vars(); if var_id < num_permanent_vars { self.permanent_state.get_var(var_id) diff --git a/crates/nu-protocol/src/lib.rs b/crates/nu-protocol/src/lib.rs index f60956b85..2b20c5e03 100644 --- a/crates/nu-protocol/src/lib.rs +++ b/crates/nu-protocol/src/lib.rs @@ -12,7 +12,7 @@ mod span; mod syntax_shape; mod ty; mod value; -pub use value::Value; +mod variable; pub use config::*; pub use engine::{CONFIG_VARIABLE_ID, ENV_VARIABLE_ID, IN_VARIABLE_ID, NU_VARIABLE_ID}; @@ -26,5 +26,5 @@ pub use signature::*; pub use span::*; pub use syntax_shape::*; pub use ty::*; -pub use value::CustomValue; pub use value::*; +pub use variable::*; diff --git a/crates/nu-protocol/src/variable.rs b/crates/nu-protocol/src/variable.rs new file mode 100644 index 000000000..f6acaf680 --- /dev/null +++ b/crates/nu-protocol/src/variable.rs @@ -0,0 +1,16 @@ +use crate::{Span, Type}; + +#[derive(Clone, Debug)] +pub struct Variable { + pub declaration_span: Span, + pub ty: Type, +} + +impl Variable { + pub fn new(declaration_span: Span, ty: Type) -> Variable { + Self { + declaration_span, + ty, + } + } +}