From e4ce41ba151f7c212c15c35ba9815664bc6916d9 Mon Sep 17 00:00:00 2001 From: JT Date: Sun, 10 Oct 2021 05:10:46 +1300 Subject: [PATCH] Fix the for loop to create vars --- crates/nu-command/src/core_commands/mod.rs | 2 + crates/nu-command/src/filters/for_.rs | 132 --------------------- crates/nu-command/src/filters/mod.rs | 2 - crates/nu-parser/src/parser.rs | 8 ++ crates/nu-protocol/src/signature.rs | 8 ++ src/tests.rs | 5 + 6 files changed, 23 insertions(+), 134 deletions(-) delete mode 100644 crates/nu-command/src/filters/for_.rs diff --git a/crates/nu-command/src/core_commands/mod.rs b/crates/nu-command/src/core_commands/mod.rs index 7418026a56..a124ffcf18 100644 --- a/crates/nu-command/src/core_commands/mod.rs +++ b/crates/nu-command/src/core_commands/mod.rs @@ -2,6 +2,7 @@ mod alias; mod def; mod do_; mod export_def; +mod for_; mod help; mod hide; mod if_; @@ -14,6 +15,7 @@ pub use alias::Alias; pub use def::Def; pub use do_::Do; pub use export_def::ExportDef; +pub use for_::For; pub use help::Help; pub use hide::Hide; pub use if_::If; diff --git a/crates/nu-command/src/filters/for_.rs b/crates/nu-command/src/filters/for_.rs deleted file mode 100644 index a3dfa56522..0000000000 --- a/crates/nu-command/src/filters/for_.rs +++ /dev/null @@ -1,132 +0,0 @@ -use nu_engine::{eval_block, eval_expression}; -use nu_protocol::ast::Call; -use nu_protocol::engine::{Command, EvaluationContext}; -use nu_protocol::{Example, IntoValueStream, Signature, Span, SyntaxShape, Value}; - -pub struct For; - -impl Command for For { - fn name(&self) -> &str { - "for" - } - - fn usage(&self) -> &str { - "Loop over a range" - } - - fn signature(&self) -> nu_protocol::Signature { - Signature::build("for") - .required( - "var_name", - SyntaxShape::Variable, - "name of the looping variable", - ) - .required( - "range", - SyntaxShape::Keyword( - b"in".to_vec(), - Box::new(SyntaxShape::List(Box::new(SyntaxShape::Int))), - ), - "range of the loop", - ) - .required( - "block", - SyntaxShape::Block(Some(vec![])), - "the block to run", - ) - } - - fn run( - &self, - context: &EvaluationContext, - call: &Call, - _input: Value, - ) -> Result { - let var_id = call.positional[0] - .as_var() - .expect("internal error: missing variable"); - - let keyword_expr = call.positional[1] - .as_keyword() - .expect("internal error: missing keyword"); - let values = eval_expression(context, keyword_expr)?; - - let block = call.positional[2] - .as_block() - .expect("internal error: expected block"); - let context = context.clone(); - - match values { - Value::Stream { stream, .. } => Ok(Value::Stream { - stream: stream - .map(move |x| { - let engine_state = context.engine_state.borrow(); - let block = engine_state.get_block(block); - - let state = context.enter_scope(); - state.add_var(var_id, x); - - //FIXME: DON'T UNWRAP - eval_block(&state, block, Value::nothing()).unwrap() - }) - .into_value_stream(), - span: call.head, - }), - Value::List { vals: val, .. } => Ok(Value::List { - vals: val - .into_iter() - .map(move |x| { - let engine_state = context.engine_state.borrow(); - let block = engine_state.get_block(block); - - let state = context.enter_scope(); - state.add_var(var_id, x); - - //FIXME: DON'T UNWRAP - eval_block(&state, block, Value::nothing()).unwrap() - }) - .collect(), - span: call.head, - }), - _ => Ok(Value::nothing()), - } - } - - fn examples(&self) -> Vec { - let span = Span::unknown(); - vec![ - Example { - description: "Echo the square of each integer", - example: "for x in [1 2 3] { $x * $x }", - result: Some(vec![ - Value::Int { val: 1, span }, - Value::Int { val: 4, span }, - Value::Int { val: 9, span }, - ]), - }, - Example { - description: "Work with elements of a range", - example: "for $x in 1..3 { $x }", - result: Some(vec![ - Value::Int { val: 1, span }, - Value::Int { val: 2, span }, - Value::Int { val: 3, span }, - ]), - }, - Example { - description: "Number each item and echo a message", - example: "for $it in ['bob' 'fred'] --numbered { $\"($it.index) is ($it.item)\" }", - result: Some(vec![ - Value::String { - val: "0 is bob".into(), - span, - }, - Value::String { - val: "0 is fred".into(), - span, - }, - ]), - }, - ] - } -} diff --git a/crates/nu-command/src/filters/mod.rs b/crates/nu-command/src/filters/mod.rs index c905721569..e4e68902da 100644 --- a/crates/nu-command/src/filters/mod.rs +++ b/crates/nu-command/src/filters/mod.rs @@ -1,5 +1,4 @@ mod each; -mod for_; mod get; mod length; mod lines; @@ -8,7 +7,6 @@ mod where_; mod wrap; pub use each::Each; -pub use for_::For; pub use get::Get; pub use length::Length; pub use lines::Lines; diff --git a/crates/nu-parser/src/parser.rs b/crates/nu-parser/src/parser.rs index dbd2ddc298..e1cdcb9781 100644 --- a/crates/nu-parser/src/parser.rs +++ b/crates/nu-parser/src/parser.rs @@ -459,6 +459,10 @@ pub fn parse_internal_call( let signature = working_set.get_decl(decl_id).signature(); + if signature.creates_scope { + working_set.enter_scope(); + } + // The index into the positional parameter in the definition let mut positional_idx = 0; @@ -554,6 +558,10 @@ pub fn parse_internal_call( let err = check_call(command_span, &signature, &call); error = error.or(err); + if signature.creates_scope { + working_set.exit_scope(); + } + // FIXME: type unknown (Box::new(call), span(spans), error) } diff --git a/crates/nu-protocol/src/signature.rs b/crates/nu-protocol/src/signature.rs index 49bae4280f..d1abc77330 100644 --- a/crates/nu-protocol/src/signature.rs +++ b/crates/nu-protocol/src/signature.rs @@ -36,6 +36,7 @@ pub struct Signature { pub rest_positional: Option, pub named: Vec, pub is_filter: bool, + pub creates_scope: bool, } impl PartialEq for Signature { @@ -62,6 +63,7 @@ impl Signature { rest_positional: None, named: vec![], is_filter: false, + creates_scope: false, } } pub fn build(name: impl Into) -> Signature { @@ -189,6 +191,12 @@ impl Signature { self } + /// Sets that signature will create a scope as it parses + pub fn creates_scope(mut self) -> Signature { + self.creates_scope = true; + self + } + /// Get list of the short-hand flags pub fn get_shorts(&self) -> Vec { self.named.iter().filter_map(|f| f.short).collect() diff --git a/src/tests.rs b/src/tests.rs index b3921acbf4..efe6be14e4 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -553,3 +553,8 @@ fn split_column() -> TestResult { "hello", ) } + +#[test] +fn for_loops() -> TestResult { + run_test(r#"(for x in [1, 2, 3] { $x + 10 }).1"#, "12") +}