mirror of
https://github.com/nushell/nushell
synced 2025-01-15 14:44:14 +00:00
Fix the for loop to create vars
This commit is contained in:
parent
9a3b0312d2
commit
e4ce41ba15
6 changed files with 23 additions and 134 deletions
|
@ -2,6 +2,7 @@ mod alias;
|
||||||
mod def;
|
mod def;
|
||||||
mod do_;
|
mod do_;
|
||||||
mod export_def;
|
mod export_def;
|
||||||
|
mod for_;
|
||||||
mod help;
|
mod help;
|
||||||
mod hide;
|
mod hide;
|
||||||
mod if_;
|
mod if_;
|
||||||
|
@ -14,6 +15,7 @@ pub use alias::Alias;
|
||||||
pub use def::Def;
|
pub use def::Def;
|
||||||
pub use do_::Do;
|
pub use do_::Do;
|
||||||
pub use export_def::ExportDef;
|
pub use export_def::ExportDef;
|
||||||
|
pub use for_::For;
|
||||||
pub use help::Help;
|
pub use help::Help;
|
||||||
pub use hide::Hide;
|
pub use hide::Hide;
|
||||||
pub use if_::If;
|
pub use if_::If;
|
||||||
|
|
|
@ -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<nu_protocol::Value, nu_protocol::ShellError> {
|
|
||||||
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<Example> {
|
|
||||||
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,
|
|
||||||
},
|
|
||||||
]),
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +1,4 @@
|
||||||
mod each;
|
mod each;
|
||||||
mod for_;
|
|
||||||
mod get;
|
mod get;
|
||||||
mod length;
|
mod length;
|
||||||
mod lines;
|
mod lines;
|
||||||
|
@ -8,7 +7,6 @@ mod where_;
|
||||||
mod wrap;
|
mod wrap;
|
||||||
|
|
||||||
pub use each::Each;
|
pub use each::Each;
|
||||||
pub use for_::For;
|
|
||||||
pub use get::Get;
|
pub use get::Get;
|
||||||
pub use length::Length;
|
pub use length::Length;
|
||||||
pub use lines::Lines;
|
pub use lines::Lines;
|
||||||
|
|
|
@ -459,6 +459,10 @@ pub fn parse_internal_call(
|
||||||
|
|
||||||
let signature = working_set.get_decl(decl_id).signature();
|
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
|
// The index into the positional parameter in the definition
|
||||||
let mut positional_idx = 0;
|
let mut positional_idx = 0;
|
||||||
|
|
||||||
|
@ -554,6 +558,10 @@ pub fn parse_internal_call(
|
||||||
let err = check_call(command_span, &signature, &call);
|
let err = check_call(command_span, &signature, &call);
|
||||||
error = error.or(err);
|
error = error.or(err);
|
||||||
|
|
||||||
|
if signature.creates_scope {
|
||||||
|
working_set.exit_scope();
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: type unknown
|
// FIXME: type unknown
|
||||||
(Box::new(call), span(spans), error)
|
(Box::new(call), span(spans), error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ pub struct Signature {
|
||||||
pub rest_positional: Option<PositionalArg>,
|
pub rest_positional: Option<PositionalArg>,
|
||||||
pub named: Vec<Flag>,
|
pub named: Vec<Flag>,
|
||||||
pub is_filter: bool,
|
pub is_filter: bool,
|
||||||
|
pub creates_scope: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for Signature {
|
impl PartialEq for Signature {
|
||||||
|
@ -62,6 +63,7 @@ impl Signature {
|
||||||
rest_positional: None,
|
rest_positional: None,
|
||||||
named: vec![],
|
named: vec![],
|
||||||
is_filter: false,
|
is_filter: false,
|
||||||
|
creates_scope: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn build(name: impl Into<String>) -> Signature {
|
pub fn build(name: impl Into<String>) -> Signature {
|
||||||
|
@ -189,6 +191,12 @@ impl Signature {
|
||||||
self
|
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
|
/// Get list of the short-hand flags
|
||||||
pub fn get_shorts(&self) -> Vec<char> {
|
pub fn get_shorts(&self) -> Vec<char> {
|
||||||
self.named.iter().filter_map(|f| f.short).collect()
|
self.named.iter().filter_map(|f| f.short).collect()
|
||||||
|
|
|
@ -553,3 +553,8 @@ fn split_column() -> TestResult {
|
||||||
"hello",
|
"hello",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn for_loops() -> TestResult {
|
||||||
|
run_test(r#"(for x in [1, 2, 3] { $x + 10 }).1"#, "12")
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue