This commit is contained in:
JT 2021-09-12 09:26:35 +12:00
parent 2d3a56f0d3
commit 55aa70c88a
5 changed files with 81 additions and 7 deletions

View File

@ -19,6 +19,8 @@
- [x] Iteration (`each`) over tables - [x] Iteration (`each`) over tables
- [x] Row conditions - [x] Row conditions
- [x] Simple completions - [x] Simple completions
- [ ] Detecting `$it` currently only looks at top scope but should find any free `$it` in the expression (including subexprs)
- [ ] Signature needs to make parameters visible in scope before block is parsed
- [ ] Value serialization - [ ] Value serialization
- [ ] Handling rows with missing columns during a cell path - [ ] Handling rows with missing columns during a cell path
- [ ] Error shortcircuit (stopping on first error) - [ ] Error shortcircuit (stopping on first error)

View File

@ -15,7 +15,9 @@ impl Command for Each {
} }
fn signature(&self) -> nu_protocol::Signature { fn signature(&self) -> nu_protocol::Signature {
Signature::build("each").required("block", SyntaxShape::Block, "the block to run") Signature::build("each")
.required("block", SyntaxShape::Block, "the block to run")
.switch("numbered", "iterate with an index", Some('n'))
} }
fn run( fn run(
@ -27,20 +29,42 @@ impl Command for Each {
let block_id = call.positional[0] let block_id = call.positional[0]
.as_block() .as_block()
.expect("internal error: expected block"); .expect("internal error: expected block");
let numbered = call.has_flag("numbered");
let context = context.clone(); let context = context.clone();
let span = call.head;
match input { match input {
Value::Range { val, .. } => Ok(Value::Stream { Value::Range { val, .. } => Ok(Value::Stream {
stream: val stream: val
.into_iter() .into_iter()
.map(move |x| { .enumerate()
.map(move |(idx, x)| {
let engine_state = context.engine_state.borrow(); let engine_state = context.engine_state.borrow();
let block = engine_state.get_block(block_id); let block = engine_state.get_block(block_id);
let state = context.enter_scope(); let state = context.enter_scope();
if let Some(var) = block.signature.get_positional(0) { if let Some(var) = block.signature.get_positional(0) {
if let Some(var_id) = &var.var_id { if let Some(var_id) = &var.var_id {
state.add_var(*var_id, x); if numbered {
state.add_var(
*var_id,
Value::Record {
cols: vec!["index".into(), "item".into()],
vals: vec![
Value::Int {
val: idx as i64,
span,
},
x,
],
span,
},
);
} else {
state.add_var(*var_id, x);
}
} }
} }
@ -55,14 +79,32 @@ impl Command for Each {
Value::List { vals: val, .. } => Ok(Value::Stream { Value::List { vals: val, .. } => Ok(Value::Stream {
stream: val stream: val
.into_iter() .into_iter()
.map(move |x| { .enumerate()
.map(move |(idx, x)| {
let engine_state = context.engine_state.borrow(); let engine_state = context.engine_state.borrow();
let block = engine_state.get_block(block_id); let block = engine_state.get_block(block_id);
let state = context.enter_scope(); let state = context.enter_scope();
if let Some(var) = block.signature.get_positional(0) { if let Some(var) = block.signature.get_positional(0) {
if let Some(var_id) = &var.var_id { if let Some(var_id) = &var.var_id {
state.add_var(*var_id, x); if numbered {
state.add_var(
*var_id,
Value::Record {
cols: vec!["index".into(), "item".into()],
vals: vec![
Value::Int {
val: idx as i64,
span,
},
x,
],
span,
},
);
} else {
state.add_var(*var_id, x);
}
} }
} }
@ -76,14 +118,32 @@ impl Command for Each {
}), }),
Value::Stream { stream, .. } => Ok(Value::Stream { Value::Stream { stream, .. } => Ok(Value::Stream {
stream: stream stream: stream
.map(move |x| { .enumerate()
.map(move |(idx, x)| {
let engine_state = context.engine_state.borrow(); let engine_state = context.engine_state.borrow();
let block = engine_state.get_block(block_id); let block = engine_state.get_block(block_id);
let state = context.enter_scope(); let state = context.enter_scope();
if let Some(var) = block.signature.get_positional(0) { if let Some(var) = block.signature.get_positional(0) {
if let Some(var_id) = &var.var_id { if let Some(var_id) = &var.var_id {
state.add_var(*var_id, x); if numbered {
state.add_var(
*var_id,
Value::Record {
cols: vec!["index".into(), "item".into()],
vals: vec![
Value::Int {
val: idx as i64,
span,
},
x,
],
span,
},
);
} else {
state.add_var(*var_id, x);
}
} }
} }

View File

@ -1992,6 +1992,7 @@ pub fn parse_block_expression(
if let Some(signature) = signature { if let Some(signature) = signature {
output.signature = signature; output.signature = signature;
} else if let Some(last) = working_set.delta.scope.last() { } else if let Some(last) = working_set.delta.scope.last() {
// FIXME: this only supports the top $it. Instead, we should look for a free $it in the expression.
if let Some(var_id) = last.get_var(b"$it") { if let Some(var_id) = last.get_var(b"$it") {
let mut signature = Signature::new(""); let mut signature = Signature::new("");
signature.required_positional.push(PositionalArg { signature.required_positional.push(PositionalArg {

View File

@ -20,6 +20,7 @@ pub fn math_result_type(
op: &mut Expression, op: &mut Expression,
rhs: &mut Expression, rhs: &mut Expression,
) -> (Type, Option<ParseError>) { ) -> (Type, Option<ParseError>) {
//println!("checking: {:?} {:?} {:?}", lhs, op, rhs);
match &op.expr { match &op.expr {
Expr::Operator(operator) => match operator { Expr::Operator(operator) => match operator {
Operator::Plus => match (&lhs.ty, &rhs.ty) { Operator::Plus => match (&lhs.ty, &rhs.ty) {

View File

@ -25,4 +25,14 @@ impl Call {
named: vec![], named: vec![],
} }
} }
pub fn has_flag(&self, flag_name: &str) -> bool {
for name in &self.named {
if flag_name == name.0 {
return true;
}
}
false
}
} }