mirror of
https://github.com/nushell/nushell
synced 2024-11-10 23:24: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 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;
|
||||
|
|
|
@ -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 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;
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ pub struct Signature {
|
|||
pub rest_positional: Option<PositionalArg>,
|
||||
pub named: Vec<Flag>,
|
||||
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<String>) -> 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<char> {
|
||||
self.named.iter().filter_map(|f| f.short).collect()
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue