Fixing captures (#723)

* WIP fixing captures

* small fix

* WIP

* Rewrite to proof-of-concept better parse_def

* Add missing file

* Finish capture refactor

* Fix tests

* Add more tests
This commit is contained in:
JT
2022-01-12 15:06:56 +11:00
committed by GitHub
parent 47495715a6
commit 186da4d725
30 changed files with 424 additions and 164 deletions

View File

@ -1,6 +1,6 @@
use nu_engine::{eval_block, CallExt};
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack};
use nu_protocol::{Category, PipelineData, Signature, SyntaxShape, Value};
#[derive(Clone)]
@ -39,16 +39,12 @@ impl Command for Do {
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let block: Value = call.req(engine_state, stack, 0)?;
let block_id = block.as_block()?;
let block: CaptureBlock = call.req(engine_state, stack, 0)?;
let rest: Vec<Value> = call.rest(engine_state, stack, 1)?;
let ignore_errors = call.has_flag("ignore-errors");
let rest: Vec<Value> = call.rest(engine_state, stack, 1)?;
let block = engine_state.get_block(block_id);
let mut stack = stack.collect_captures(&block.captures);
let mut stack = stack.captures_to_stack(&block.captures);
let block = engine_state.get_block(block.block_id);
let params: Vec<_> = block
.signature

View File

@ -1,6 +1,6 @@
use nu_engine::{eval_block, eval_expression};
use nu_engine::{eval_block, eval_expression, CallExt};
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack};
use nu_protocol::{
Category, Example, IntoInterruptiblePipelineData, PipelineData, Signature, Span, SyntaxShape,
Value,
@ -61,16 +61,14 @@ impl Command for For {
.expect("internal error: missing keyword");
let values = eval_expression(engine_state, stack, keyword_expr)?;
let block_id = call.positional[2]
.as_block()
.expect("internal error: expected block");
let capture_block: CaptureBlock = call.req(engine_state, stack, 2)?;
let numbered = call.has_flag("numbered");
let ctrlc = engine_state.ctrlc.clone();
let engine_state = engine_state.clone();
let block = engine_state.get_block(block_id).clone();
let mut stack = stack.collect_captures(&block.captures);
let block = engine_state.get_block(capture_block.block_id).clone();
let mut stack = stack.captures_to_stack(&capture_block.captures);
let orig_env_vars = stack.env_vars.clone();
let orig_env_hidden = stack.env_hidden.clone();

View File

@ -1,8 +1,9 @@
use nu_engine::{eval_block, eval_expression};
use nu_engine::{eval_block, eval_expression, CallExt};
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack};
use nu_protocol::{
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, Value,
Category, Example, FromValue, IntoPipelineData, PipelineData, ShellError, Signature,
SyntaxShape, Value,
};
#[derive(Clone)]
@ -41,23 +42,24 @@ impl Command for If {
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let cond = &call.positional[0];
let then_block = call.positional[1]
.as_block()
.expect("internal error: expected block");
let then_block: CaptureBlock = call.req(engine_state, stack, 1)?;
let else_case = call.positional.get(2);
let result = eval_expression(engine_state, stack, cond)?;
match &result {
Value::Bool { val, .. } => {
if *val {
let block = engine_state.get_block(then_block);
let mut stack = stack.collect_captures(&block.captures);
let block = engine_state.get_block(then_block.block_id);
let mut stack = stack.captures_to_stack(&then_block.captures);
eval_block(engine_state, &mut stack, block, input)
} else if let Some(else_case) = else_case {
if let Some(else_expr) = else_case.as_keyword() {
if let Some(block_id) = else_expr.as_block() {
let result = eval_expression(engine_state, stack, else_expr)?;
let else_block: CaptureBlock = FromValue::from_value(&result)?;
let mut stack = stack.captures_to_stack(&else_block.captures);
let block = engine_state.get_block(block_id);
let mut stack = stack.collect_captures(&block.captures);
eval_block(engine_state, &mut stack, block, input)
} else {
eval_expression(engine_state, stack, else_expr)

View File

@ -3,7 +3,7 @@ use std::collections::HashMap;
use nu_engine::{eval_block, CallExt};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
engine::{CaptureBlock, Command, EngineState, Stack},
Category, Example, PipelineData, ShellError, Signature, SyntaxShape, Value,
};
@ -79,11 +79,9 @@ fn with_env(
// let external_redirection = args.call_info.args.external_redirection;
let variable: Value = call.req(engine_state, stack, 0)?;
let block_id = call.positional[1]
.as_block()
.expect("internal error: expected block");
let block = engine_state.get_block(block_id).clone();
let mut stack = stack.collect_captures(&block.captures);
let capture_block: CaptureBlock = call.req(engine_state, stack, 1)?;
let block = engine_state.get_block(capture_block.block_id);
let mut stack = stack.captures_to_stack(&capture_block.captures);
let mut env: HashMap<String, Value> = HashMap::new();
@ -134,7 +132,7 @@ fn with_env(
stack.add_env_var(k, v);
}
eval_block(engine_state, &mut stack, &block, input)
eval_block(engine_state, &mut stack, block, input)
}
#[cfg(test)]

View File

@ -1,7 +1,7 @@
use nu_engine::eval_block;
use nu_engine::{eval_block, CallExt};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
engine::{CaptureBlock, Command, EngineState, Stack},
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, Value,
};
@ -49,16 +49,15 @@ impl Command for All {
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let predicate = &call.positional[0];
// let predicate = &call.positional[0];
let span = call.head;
let block_id = predicate
.as_row_condition_block()
.ok_or_else(|| ShellError::TypeMismatch("expected row condition".to_owned(), span))?;
let capture_block: CaptureBlock = call.req(engine_state, stack, 0)?;
let block_id = capture_block.block_id;
let block = engine_state.get_block(block_id);
let var_id = block.signature.get_positional(0).and_then(|arg| arg.var_id);
let mut stack = stack.collect_captures(&block.captures);
let mut stack = stack.captures_to_stack(&capture_block.captures);
let ctrlc = engine_state.ctrlc.clone();
let engine_state = engine_state.clone();

View File

@ -1,7 +1,7 @@
use nu_engine::eval_block;
use nu_engine::{eval_block, CallExt};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
engine::{CaptureBlock, Command, EngineState, Stack},
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, SyntaxShape, Value,
};
@ -49,16 +49,14 @@ impl Command for Any {
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let predicate = &call.positional[0];
let span = call.head;
let block_id = predicate
.as_row_condition_block()
.ok_or_else(|| ShellError::TypeMismatch("expected row condition".to_owned(), span))?;
let capture_block: CaptureBlock = call.req(engine_state, stack, 0)?;
let block_id = capture_block.block_id;
let block = engine_state.get_block(block_id);
let var_id = block.signature.get_positional(0).and_then(|arg| arg.var_id);
let mut stack = stack.collect_captures(&block.captures);
let mut stack = stack.captures_to_stack(&capture_block.captures);
let ctrlc = engine_state.ctrlc.clone();
let engine_state = engine_state.clone();

View File

@ -1,6 +1,6 @@
use nu_engine::eval_block;
use nu_engine::{eval_block, CallExt};
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack};
use nu_protocol::{Category, Example, PipelineData, Signature, SyntaxShape, Value};
#[derive(Clone)]
@ -32,12 +32,10 @@ impl Command for Collect {
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let block_id = call.positional[0]
.as_block()
.expect("internal error: expected block");
let capture_block: CaptureBlock = call.req(engine_state, stack, 0)?;
let block = engine_state.get_block(block_id).clone();
let mut stack = stack.collect_captures(&block.captures);
let block = engine_state.get_block(capture_block.block_id).clone();
let mut stack = stack.captures_to_stack(&capture_block.captures);
let input: Value = input.into_value(call.head);

View File

@ -1,6 +1,6 @@
use nu_engine::eval_block;
use nu_engine::{eval_block, CallExt};
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack};
use nu_protocol::{
Category, Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, Signature,
Span, SyntaxShape, Value,
@ -62,15 +62,13 @@ impl Command for Each {
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let block_id = call.positional[0]
.as_block()
.expect("internal error: expected block");
let capture_block: CaptureBlock = call.req(engine_state, stack, 0)?;
let numbered = call.has_flag("numbered");
let ctrlc = engine_state.ctrlc.clone();
let engine_state = engine_state.clone();
let block = engine_state.get_block(block_id).clone();
let mut stack = stack.collect_captures(&block.captures);
let block = engine_state.get_block(capture_block.block_id).clone();
let mut stack = stack.captures_to_stack(&capture_block.captures);
let orig_env_vars = stack.env_vars.clone();
let orig_env_hidden = stack.env_hidden.clone();
let span = call.head;
@ -198,7 +196,7 @@ impl Command for Each {
let mut output_vals = vec![];
for (col, val) in cols.into_iter().zip(vals.into_iter()) {
let block = engine_state.get_block(block_id);
//let block = engine_state.get_block(block_id);
stack.with_env(&orig_env_vars, &orig_env_hidden);
@ -221,7 +219,7 @@ impl Command for Each {
}
}
match eval_block(&engine_state, &mut stack, block, PipelineData::new(span))? {
match eval_block(&engine_state, &mut stack, &block, PipelineData::new(span))? {
PipelineData::Value(
Value::Record {
mut cols, mut vals, ..
@ -247,7 +245,7 @@ impl Command for Each {
.into_pipeline_data())
}
PipelineData::Value(x, ..) => {
let block = engine_state.get_block(block_id);
//let block = engine_state.get_block(block_id);
if let Some(var) = block.signature.get_positional(0) {
if let Some(var_id) = &var.var_id {
@ -255,7 +253,7 @@ impl Command for Each {
}
}
eval_block(&engine_state, &mut stack, block, PipelineData::new(span))
eval_block(&engine_state, &mut stack, &block, PipelineData::new(span))
}
}
}

View File

@ -1,7 +1,7 @@
use nu_engine::eval_block;
use nu_engine::{eval_block, CallExt};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
engine::{CaptureBlock, Command, EngineState, Stack},
Category, Example, IntoInterruptiblePipelineData, PipelineData, ShellError, Signature, Span,
SyntaxShape, Value,
};
@ -48,15 +48,12 @@ impl Command for KeepUntil {
) -> Result<PipelineData, ShellError> {
let span = call.head;
let predicate = &call.positional[0];
let block_id = predicate
.as_row_condition_block()
.ok_or_else(|| ShellError::TypeMismatch("expected row condition".to_owned(), span))?;
let capture_block: CaptureBlock = call.req(engine_state, stack, 0)?;
let block = engine_state.get_block(block_id).clone();
let block = engine_state.get_block(capture_block.block_id).clone();
let var_id = block.signature.get_positional(0).and_then(|arg| arg.var_id);
let mut stack = stack.collect_captures(&block.captures);
let mut stack = stack.captures_to_stack(&capture_block.captures);
let ctrlc = engine_state.ctrlc.clone();
let engine_state = engine_state.clone();

View File

@ -1,7 +1,7 @@
use nu_engine::eval_block;
use nu_engine::{eval_block, CallExt};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
engine::{CaptureBlock, Command, EngineState, Stack},
Category, Example, IntoInterruptiblePipelineData, PipelineData, ShellError, Signature, Span,
SyntaxShape, Value,
};
@ -48,15 +48,12 @@ impl Command for KeepWhile {
) -> Result<PipelineData, ShellError> {
let span = call.head;
let predicate = &call.positional[0];
let block_id = predicate
.as_row_condition_block()
.ok_or_else(|| ShellError::TypeMismatch("expected row condition".to_owned(), span))?;
let capture_block: CaptureBlock = call.req(engine_state, stack, 0)?;
let block = engine_state.get_block(block_id).clone();
let block = engine_state.get_block(capture_block.block_id).clone();
let var_id = block.signature.get_positional(0).and_then(|arg| arg.var_id);
let mut stack = stack.collect_captures(&block.captures);
let mut stack = stack.captures_to_stack(&capture_block.captures);
let ctrlc = engine_state.ctrlc.clone();
let engine_state = engine_state.clone();

View File

@ -1,6 +1,6 @@
use nu_engine::eval_block;
use nu_engine::{eval_block, CallExt};
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack};
use nu_protocol::{
Category, Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, Signature,
SyntaxShape, Value,
@ -45,15 +45,13 @@ impl Command for ParEach {
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let block_id = call.positional[0]
.as_block()
.expect("internal error: expected block");
let capture_block: CaptureBlock = call.req(engine_state, stack, 0)?;
let numbered = call.has_flag("numbered");
let ctrlc = engine_state.ctrlc.clone();
let engine_state = engine_state.clone();
let block = engine_state.get_block(block_id);
let mut stack = stack.collect_captures(&block.captures);
let block_id = capture_block.block_id;
let mut stack = stack.captures_to_stack(&capture_block.captures);
let span = call.head;
match input {

View File

@ -1,7 +1,7 @@
use nu_engine::{eval_block, CallExt};
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack};
use nu_protocol::{
Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape, Value,
};
@ -102,17 +102,10 @@ impl Command for Reduce {
let fold: Option<Value> = call.get_flag(engine_state, stack, "fold")?;
let numbered = call.has_flag("numbered");
let block = if let Some(block_id) = call.nth(0).and_then(|b| b.as_block()) {
engine_state.get_block(block_id)
} else {
return Err(ShellError::SpannedLabeledError(
"Internal Error".to_string(),
"expected block".to_string(),
span,
));
};
let capture_block: CaptureBlock = call.req(engine_state, stack, 0)?;
let mut stack = stack.captures_to_stack(&capture_block.captures);
let block = engine_state.get_block(capture_block.block_id);
let mut stack = stack.collect_captures(&block.captures);
let orig_env_vars = stack.env_vars.clone();
let orig_env_hidden = stack.env_hidden.clone();

View File

@ -1,7 +1,7 @@
use nu_engine::eval_block;
use nu_engine::{eval_block, CallExt};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
engine::{CaptureBlock, Command, EngineState, Stack},
Category, Example, IntoInterruptiblePipelineData, PipelineData, ShellError, Signature, Span,
SyntaxShape, Value,
};
@ -46,16 +46,13 @@ impl Command for SkipUntil {
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let predicate = &call.positional[0];
let span = call.head;
let block_id = predicate
.as_row_condition_block()
.ok_or_else(|| ShellError::TypeMismatch("expected row condition".to_owned(), span))?;
let capture_block: CaptureBlock = call.req(engine_state, stack, 0)?;
let block = engine_state.get_block(block_id).clone();
let block = engine_state.get_block(capture_block.block_id).clone();
let var_id = block.signature.get_positional(0).and_then(|arg| arg.var_id);
let mut stack = stack.collect_captures(&block.captures);
let mut stack = stack.captures_to_stack(&capture_block.captures);
let ctrlc = engine_state.ctrlc.clone();
let engine_state = engine_state.clone();

View File

@ -1,7 +1,7 @@
use nu_engine::eval_block;
use nu_engine::{eval_block, CallExt};
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
engine::{CaptureBlock, Command, EngineState, Stack},
Category, Example, IntoInterruptiblePipelineData, PipelineData, ShellError, Signature, Span,
SyntaxShape, Value,
};
@ -46,16 +46,13 @@ impl Command for SkipWhile {
call: &Call,
input: PipelineData,
) -> Result<PipelineData, ShellError> {
let predicate = &call.positional[0];
let span = call.head;
let block_id = predicate
.as_row_condition_block()
.ok_or_else(|| ShellError::TypeMismatch("expected row condition".to_owned(), span))?;
let capture_block: CaptureBlock = call.req(engine_state, stack, 0)?;
let block = engine_state.get_block(block_id).clone();
let block = engine_state.get_block(capture_block.block_id).clone();
let var_id = block.signature.get_positional(0).and_then(|arg| arg.var_id);
let mut stack = stack.collect_captures(&block.captures);
let mut stack = stack.captures_to_stack(&capture_block.captures);
let ctrlc = engine_state.ctrlc.clone();
let engine_state = engine_state.clone();

View File

@ -1,9 +1,9 @@
use nu_engine::{eval_block, CallExt};
use nu_protocol::ast::{Call, CellPath};
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack};
use nu_protocol::{
Category, Example, IntoPipelineData, PipelineData, ShellError, Signature, Span, SyntaxShape,
Value,
Category, Example, FromValue, IntoPipelineData, PipelineData, ShellError, Signature, Span,
SyntaxShape, Value,
};
#[derive(Clone)]
@ -70,10 +70,11 @@ fn update(
let ctrlc = engine_state.ctrlc.clone();
// Replace is a block, so set it up and run it instead of using it as the replacement
if let Ok(block_id) = replacement.as_block() {
let block = engine_state.get_block(block_id).clone();
if replacement.as_block().is_ok() {
let capture_block: CaptureBlock = FromValue::from_value(&replacement)?;
let block = engine_state.get_block(capture_block.block_id).clone();
let mut stack = stack.collect_captures(&block.captures);
let mut stack = stack.captures_to_stack(&capture_block.captures);
let orig_env_vars = stack.env_vars.clone();
let orig_env_hidden = stack.env_hidden.clone();

View File

@ -1,7 +1,7 @@
use nu_engine::eval_block;
use nu_engine::{eval_block, CallExt};
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::{Category, PipelineData, ShellError, Signature, SyntaxShape};
use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack};
use nu_protocol::{Category, PipelineData, Signature, SyntaxShape};
#[derive(Clone)]
pub struct Where;
@ -28,21 +28,17 @@ impl Command for Where {
call: &Call,
input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let cond = &call.positional[0];
let span = call.head;
let metadata = input.metadata();
let block_id = cond
.as_row_condition_block()
.ok_or_else(|| ShellError::TypeMismatch("expected row condition".to_owned(), span))?;
let block: CaptureBlock = call.req(engine_state, stack, 0)?;
let mut stack = stack.captures_to_stack(&block.captures);
let block = engine_state.get_block(block.block_id).clone();
let ctrlc = engine_state.ctrlc.clone();
let engine_state = engine_state.clone();
let block = engine_state.get_block(block_id).clone();
let mut stack = stack.collect_captures(&block.captures);
input
.filter(
move |value| {

View File

@ -1,8 +1,8 @@
use std::time::Instant;
use nu_engine::eval_block;
use nu_engine::{eval_block, CallExt};
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EngineState, Stack};
use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack};
use nu_protocol::{Category, IntoPipelineData, PipelineData, Signature, SyntaxShape, Value};
#[derive(Clone)]
@ -34,12 +34,10 @@ impl Command for Benchmark {
call: &Call,
_input: PipelineData,
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
let block = call.positional[0]
.as_block()
.expect("internal error: expected block");
let block = engine_state.get_block(block);
let capture_block: CaptureBlock = call.req(engine_state, stack, 0)?;
let block = engine_state.get_block(capture_block.block_id);
let mut stack = stack.collect_captures(&block.captures);
let mut stack = stack.captures_to_stack(&capture_block.captures);
let start_time = Instant::now();
eval_block(
engine_state,