Refactor scope (#2602)

* Refactor scope to have parents

* Refactor scope to have parents

* Refactor scope to have parents

* Clippy

Co-authored-by: Jonathan Turner <jonathan@pop-os.localdomain>
This commit is contained in:
Jonathan Turner 2020-09-26 11:40:02 +12:00 committed by GitHub
parent 9dc88f8a95
commit cb7723f423
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 288 additions and 423 deletions

View File

@ -9,7 +9,7 @@ use crate::EnvironmentSyncer;
use futures_codec::FramedRead; use futures_codec::FramedRead;
use nu_errors::ShellError; use nu_errors::ShellError;
use nu_protocol::hir::{ClassifiedCommand, Expression, InternalCommand, Literal, NamedArguments}; use nu_protocol::hir::{ClassifiedCommand, Expression, InternalCommand, Literal, NamedArguments};
use nu_protocol::{Primitive, ReturnSuccess, UntaggedValue, Value}; use nu_protocol::{Primitive, ReturnSuccess, Scope, UntaggedValue, Value};
use log::{debug, trace}; use log::{debug, trace};
#[cfg(feature = "rustyline-support")] #[cfg(feature = "rustyline-support")]
@ -395,9 +395,7 @@ pub async fn cli(mut context: EvaluationContext) -> Result<(), Box<dyn Error>> {
&prompt_block.block, &prompt_block.block,
&mut context, &mut context,
InputStream::empty(), InputStream::empty(),
&Value::nothing(), Scope::from_env(env),
&IndexMap::new(),
&env,
) )
.await .await
{ {
@ -862,9 +860,7 @@ pub async fn parse_and_eval(line: &str, ctx: &mut EvaluationContext) -> Result<S
&classified_block.block, &classified_block.block,
ctx, ctx,
input_stream, input_stream,
&Value::nothing(), Scope::from_env(env),
&IndexMap::new(),
&env,
) )
.await? .await?
.collect_string(Tag::unknown()) .collect_string(Tag::unknown())
@ -1021,9 +1017,7 @@ pub async fn process_line(
&classified_block.block, &classified_block.block,
ctx, ctx,
input_stream, input_stream,
&Value::nothing(), Scope::from_env(env),
&IndexMap::new(),
&env,
) )
.await .await
{ {

View File

@ -318,7 +318,7 @@ fn create_default_command_args(context: &RunnableContextWithoutInput) -> RawComm
external_redirection: ExternalRedirection::Stdout, external_redirection: ExternalRedirection::Stdout,
}, },
name_tag: context.name.clone(), name_tag: context.name.clone(),
scope: Scope::new(), scope: Scope::create(),
}, },
} }
} }

View File

@ -83,16 +83,18 @@ async fn benchmark(
let scope = raw_args.call_info.scope.clone(); let scope = raw_args.call_info.scope.clone();
let (BenchmarkArgs { block, passthrough }, input) = raw_args.process(&registry).await?; let (BenchmarkArgs { block, passthrough }, input) = raw_args.process(&registry).await?;
let mut env = scope.env.clone(); let env = scope.env();
let name = generate_free_name(&env); let name = generate_free_name(&env);
let mut env = IndexMap::new();
env.insert(name, generate_random_env_value()); env.insert(name, generate_random_env_value());
let scope = Scope::append_env(scope, env);
let start_time = Instant::now(); let start_time = Instant::now();
#[cfg(feature = "rich-benchmark")] #[cfg(feature = "rich-benchmark")]
let start = time().await; let start = time().await;
let result = run_block(&block, &mut context, input, &scope.it, &scope.vars, &env).await; let result = run_block(&block, &mut context, input, scope.clone()).await;
let output = result?.into_vec().await; let output = result?.into_vec().await;
#[cfg(feature = "rich-benchmark")] #[cfg(feature = "rich-benchmark")]
@ -108,7 +110,7 @@ async fn benchmark(
let real_time = into_big_int(end_time - start_time); let real_time = into_big_int(end_time - start_time);
indexmap.insert("real time".to_string(), real_time); indexmap.insert("real time".to_string(), real_time);
benchmark_output(indexmap, output, passthrough, &tag, &mut context, &scope).await benchmark_output(indexmap, output, passthrough, &tag, &mut context, scope).await
} }
// return advanced stats // return advanced stats
#[cfg(feature = "rich-benchmark")] #[cfg(feature = "rich-benchmark")]
@ -127,7 +129,7 @@ async fn benchmark(
let idle_time = into_big_int(end.idle() - start.idle()); let idle_time = into_big_int(end.idle() - start.idle());
indexmap.insert("idle time".to_string(), idle_time); indexmap.insert("idle time".to_string(), idle_time);
benchmark_output(indexmap, output, passthrough, &tag, &mut context, &scope).await benchmark_output(indexmap, output, passthrough, &tag, &mut context, scope).await
} else { } else {
Err(ShellError::untagged_runtime_error( Err(ShellError::untagged_runtime_error(
"Could not retreive CPU time", "Could not retreive CPU time",
@ -141,7 +143,7 @@ async fn benchmark_output<T, Output>(
passthrough: Option<Block>, passthrough: Option<Block>,
tag: T, tag: T,
context: &mut EvaluationContext, context: &mut EvaluationContext,
scope: &Scope, scope: Arc<Scope>,
) -> Result<OutputStream, ShellError> ) -> Result<OutputStream, ShellError>
where where
T: Into<Tag> + Copy, T: Into<Tag> + Copy,
@ -161,15 +163,7 @@ where
// add autoview for an empty block // add autoview for an empty block
let time_block = add_implicit_autoview(time_block); let time_block = add_implicit_autoview(time_block);
let _ = run_block( let _ = run_block(&time_block, context, benchmark_output, scope).await?;
&time_block,
context,
benchmark_output,
&scope.it,
&scope.vars,
&scope.env,
)
.await?;
context.clear_errors(); context.clear_errors();
Ok(block_output.into()) Ok(block_output.into())

View File

@ -6,16 +6,14 @@ use crate::stream::InputStream;
use futures::stream::TryStreamExt; use futures::stream::TryStreamExt;
use nu_errors::ShellError; use nu_errors::ShellError;
use nu_protocol::hir::{Block, ClassifiedCommand, Commands}; use nu_protocol::hir::{Block, ClassifiedCommand, Commands};
use nu_protocol::{ReturnSuccess, UntaggedValue, Value}; use nu_protocol::{ReturnSuccess, Scope, UntaggedValue, Value};
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
pub(crate) async fn run_block( pub(crate) async fn run_block(
block: &Block, block: &Block,
ctx: &mut EvaluationContext, ctx: &mut EvaluationContext,
mut input: InputStream, mut input: InputStream,
it: &Value, scope: Arc<Scope>,
vars: &IndexMap<String, Value>,
env: &IndexMap<String, String>,
) -> Result<InputStream, ShellError> { ) -> Result<InputStream, ShellError> {
let mut output: Result<InputStream, ShellError> = Ok(InputStream::empty()); let mut output: Result<InputStream, ShellError> = Ok(InputStream::empty());
for pipeline in &block.block { for pipeline in &block.block {
@ -54,7 +52,7 @@ pub(crate) async fn run_block(
return Err(e); return Err(e);
} }
} }
output = run_pipeline(pipeline, ctx, input, it, vars, env).await; output = run_pipeline(pipeline, ctx, input, scope.clone()).await;
input = InputStream::empty(); input = InputStream::empty();
} }
@ -66,9 +64,7 @@ async fn run_pipeline(
commands: &Commands, commands: &Commands,
ctx: &mut EvaluationContext, ctx: &mut EvaluationContext,
mut input: InputStream, mut input: InputStream,
it: &Value, scope: Arc<Scope>,
vars: &IndexMap<String, Value>,
env: &IndexMap<String, String>,
) -> Result<InputStream, ShellError> { ) -> Result<InputStream, ShellError> {
for item in commands.list.clone() { for item in commands.list.clone() {
input = match item { input = match item {
@ -77,13 +73,13 @@ async fn run_pipeline(
} }
ClassifiedCommand::Expr(expr) => { ClassifiedCommand::Expr(expr) => {
run_expression_block(*expr, ctx, it, vars, env).await? run_expression_block(*expr, ctx, scope.clone()).await?
} }
ClassifiedCommand::Error(err) => return Err(err.into()), ClassifiedCommand::Error(err) => return Err(err.into()),
ClassifiedCommand::Internal(left) => { ClassifiedCommand::Internal(left) => {
run_internal_command(left, ctx, input, it, vars, env).await? run_internal_command(left, ctx, input, scope.clone()).await?
} }
}; };
} }

View File

@ -6,14 +6,12 @@ use log::{log_enabled, trace};
use futures::stream::once; use futures::stream::once;
use nu_errors::ShellError; use nu_errors::ShellError;
use nu_protocol::hir::SpannedExpression; use nu_protocol::hir::SpannedExpression;
use nu_protocol::Value; use nu_protocol::Scope;
pub(crate) async fn run_expression_block( pub(crate) async fn run_expression_block(
expr: SpannedExpression, expr: SpannedExpression,
context: &mut EvaluationContext, context: &mut EvaluationContext,
it: &Value, scope: Arc<Scope>,
vars: &IndexMap<String, Value>,
env: &IndexMap<String, String>,
) -> Result<InputStream, ShellError> { ) -> Result<InputStream, ShellError> {
if log_enabled!(log::Level::Trace) { if log_enabled!(log::Level::Trace) {
trace!(target: "nu::run::expr", "->"); trace!(target: "nu::run::expr", "->");
@ -21,7 +19,7 @@ pub(crate) async fn run_expression_block(
} }
let registry = context.registry().clone(); let registry = context.registry().clone();
let output = evaluate_baseline_expr(&expr, &registry, it, vars, env).await?; let output = evaluate_baseline_expr(&expr, &registry, scope).await?;
Ok(once(async { Ok(output) }).to_input_stream()) Ok(once(async { Ok(output) }).to_input_stream())
} }

View File

@ -21,7 +21,7 @@ pub(crate) async fn run_external_command(
command: ExternalCommand, command: ExternalCommand,
context: &mut EvaluationContext, context: &mut EvaluationContext,
input: InputStream, input: InputStream,
scope: &Scope, scope: Arc<Scope>,
external_redirection: ExternalRedirection, external_redirection: ExternalRedirection,
) -> Result<InputStream, ShellError> { ) -> Result<InputStream, ShellError> {
trace!(target: "nu::run::external", "-> {}", command.name); trace!(target: "nu::run::external", "-> {}", command.name);
@ -41,7 +41,7 @@ async fn run_with_stdin(
command: ExternalCommand, command: ExternalCommand,
context: &mut EvaluationContext, context: &mut EvaluationContext,
input: InputStream, input: InputStream,
scope: &Scope, scope: Arc<Scope>,
external_redirection: ExternalRedirection, external_redirection: ExternalRedirection,
) -> Result<InputStream, ShellError> { ) -> Result<InputStream, ShellError> {
let path = context.shell_manager.path(); let path = context.shell_manager.path();
@ -50,9 +50,7 @@ async fn run_with_stdin(
let mut command_args = vec![]; let mut command_args = vec![];
for arg in command.args.iter() { for arg in command.args.iter() {
let value = let value = evaluate_baseline_expr(arg, &context.registry, scope.clone()).await?;
evaluate_baseline_expr(arg, &context.registry, &scope.it, &scope.vars, &scope.env)
.await?;
// Skip any arguments that don't really exist, treating them as optional // Skip any arguments that don't really exist, treating them as optional
// FIXME: we may want to preserve the gap in the future, though it's hard to say // FIXME: we may want to preserve the gap in the future, though it's hard to say
@ -138,7 +136,7 @@ fn spawn(
args: &[String], args: &[String],
input: InputStream, input: InputStream,
external_redirection: ExternalRedirection, external_redirection: ExternalRedirection,
scope: &Scope, scope: Arc<Scope>,
) -> Result<InputStream, ShellError> { ) -> Result<InputStream, ShellError> {
let command = command.clone(); let command = command.clone();
@ -169,7 +167,7 @@ fn spawn(
trace!(target: "nu::run::external", "cwd = {:?}", &path); trace!(target: "nu::run::external", "cwd = {:?}", &path);
process.env_clear(); process.env_clear();
process.envs(scope.env.iter()); process.envs(scope.env());
// We want stdout regardless of what // We want stdout regardless of what
// we are doing ($it case or pipe stdin) // we are doing ($it case or pipe stdin)
@ -580,7 +578,7 @@ mod tests {
cmd, cmd,
&mut ctx, &mut ctx,
input, input,
&Scope::new(), Scope::create(),
ExternalRedirection::Stdout ExternalRedirection::Stdout
) )
.await .await

View File

@ -11,20 +11,13 @@ pub(crate) async fn run_internal_command(
command: InternalCommand, command: InternalCommand,
context: &mut EvaluationContext, context: &mut EvaluationContext,
input: InputStream, input: InputStream,
it: &Value, scope: Arc<Scope>,
vars: &IndexMap<String, Value>,
env: &IndexMap<String, String>,
) -> Result<InputStream, ShellError> { ) -> Result<InputStream, ShellError> {
if log_enabled!(log::Level::Trace) { if log_enabled!(log::Level::Trace) {
trace!(target: "nu::run::internal", "->"); trace!(target: "nu::run::internal", "->");
trace!(target: "nu::run::internal", "{}", command.name); trace!(target: "nu::run::internal", "{}", command.name);
} }
let scope = Scope {
it: it.clone(),
vars: vars.clone(),
env: env.clone(),
};
let objects: InputStream = trace_stream!(target: "nu::trace_stream::internal", "input" = input); let objects: InputStream = trace_stream!(target: "nu::trace_stream::internal", "input" = input);
let internal_command = context.expect_command(&command.name); let internal_command = context.expect_command(&command.name);
@ -38,7 +31,7 @@ pub(crate) async fn run_internal_command(
internal_command?, internal_command?,
Tag::unknown_anchor(command.name_span), Tag::unknown_anchor(command.name_span),
command.args.clone(), command.args.clone(),
&scope, scope.clone(),
objects, objects,
) )
.await? .await?
@ -48,8 +41,6 @@ pub(crate) async fn run_internal_command(
//let context = Arc::new(context.clone()); //let context = Arc::new(context.clone());
let context = context.clone(); let context = context.clone();
let command = Arc::new(command); let command = Arc::new(command);
let scope = Arc::new(scope);
// let scope = scope.clone();
Ok(InputStream::from_stream( Ok(InputStream::from_stream(
result result
@ -90,7 +81,7 @@ pub(crate) async fn run_internal_command(
external_redirection: ExternalRedirection::Stdout, external_redirection: ExternalRedirection::Stdout,
}, },
name_tag: Tag::unknown_anchor(command.name_span), name_tag: Tag::unknown_anchor(command.name_span),
scope: (&*scope).clone(), scope,
}, },
}; };
let result = converter let result = converter

View File

@ -130,7 +130,7 @@ async fn run_filter(
UntaggedValue::Primitive(Primitive::EndOfStream).into_untagged_value() UntaggedValue::Primitive(Primitive::EndOfStream).into_untagged_value()
]); ]);
let args = args.evaluate_once_with_scope(&registry, &scope).await?; let args = args.evaluate_once_with_scope(&registry, scope).await?;
let real_path = Path::new(&path); let real_path = Path::new(&path);
let ext = real_path.extension(); let ext = real_path.extension();

View File

@ -17,27 +17,12 @@ use std::sync::atomic::AtomicBool;
pub struct UnevaluatedCallInfo { pub struct UnevaluatedCallInfo {
pub args: hir::Call, pub args: hir::Call,
pub name_tag: Tag, pub name_tag: Tag,
pub scope: Scope, pub scope: Arc<Scope>,
} }
impl UnevaluatedCallInfo { impl UnevaluatedCallInfo {
pub async fn evaluate(self, registry: &CommandRegistry) -> Result<CallInfo, ShellError> { pub async fn evaluate(self, registry: &CommandRegistry) -> Result<CallInfo, ShellError> {
let args = evaluate_args(&self.args, registry, &self.scope).await?; let args = evaluate_args(&self.args, registry, self.scope.clone()).await?;
Ok(CallInfo {
args,
name_tag: self.name_tag,
})
}
pub async fn evaluate_with_new_it(
self,
registry: &CommandRegistry,
it: &Value,
) -> Result<CallInfo, ShellError> {
let mut scope = self.scope.clone();
scope.it = it.clone();
let args = evaluate_args(&self.args, registry, &scope).await?;
Ok(CallInfo { Ok(CallInfo {
args, args,
@ -115,7 +100,7 @@ impl CommandArgs {
pub async fn evaluate_once_with_scope( pub async fn evaluate_once_with_scope(
self, self,
registry: &CommandRegistry, registry: &CommandRegistry,
scope: &Scope, scope: Arc<Scope>,
) -> Result<EvaluatedWholeStreamCommandArgs, ShellError> { ) -> Result<EvaluatedWholeStreamCommandArgs, ShellError> {
let host = self.host.clone(); let host = self.host.clone();
let ctrl_c = self.ctrl_c.clone(); let ctrl_c = self.ctrl_c.clone();
@ -215,37 +200,6 @@ impl EvaluatedWholeStreamCommandArgs {
} }
} }
#[derive(Getters)]
#[get = "pub"]
pub struct EvaluatedFilterCommandArgs {
args: EvaluatedCommandArgs,
}
impl Deref for EvaluatedFilterCommandArgs {
type Target = EvaluatedCommandArgs;
fn deref(&self) -> &Self::Target {
&self.args
}
}
impl EvaluatedFilterCommandArgs {
pub fn new(
host: Arc<parking_lot::Mutex<dyn Host>>,
ctrl_c: Arc<AtomicBool>,
shell_manager: ShellManager,
call_info: CallInfo,
) -> EvaluatedFilterCommandArgs {
EvaluatedFilterCommandArgs {
args: EvaluatedCommandArgs {
host,
ctrl_c,
shell_manager,
call_info,
},
}
}
}
#[derive(Getters, new)] #[derive(Getters, new)]
#[get = "pub(crate)"] #[get = "pub(crate)"]
pub struct EvaluatedCommandArgs { pub struct EvaluatedCommandArgs {
@ -381,69 +335,6 @@ impl Command {
} }
} }
pub struct FnFilterCommand {
name: String,
func: fn(EvaluatedFilterCommandArgs) -> Result<OutputStream, ShellError>,
}
#[async_trait]
impl WholeStreamCommand for FnFilterCommand {
fn name(&self) -> &str {
&self.name
}
fn usage(&self) -> &str {
"usage"
}
async fn run(
&self,
CommandArgs {
host,
ctrl_c,
shell_manager,
call_info,
input,
..
}: CommandArgs,
registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> {
let registry = Arc::new(registry.clone());
let func = self.func;
Ok(input
.then(move |it| {
let host = host.clone();
let registry = registry.clone();
let ctrl_c = ctrl_c.clone();
let shell_manager = shell_manager.clone();
let call_info = call_info.clone();
async move {
let call_info = match call_info.evaluate_with_new_it(&*registry, &it).await {
Err(err) => {
return OutputStream::one(Err(err));
}
Ok(args) => args,
};
let args = EvaluatedFilterCommandArgs::new(
host.clone(),
ctrl_c.clone(),
shell_manager.clone(),
call_info,
);
match func(args) {
Err(err) => return OutputStream::one(Err(err)),
Ok(stream) => stream,
}
}
})
.flatten()
.to_output_stream())
}
}
pub fn whole_stream_command(command: impl WholeStreamCommand + 'static) -> Command { pub fn whole_stream_command(command: impl WholeStreamCommand + 'static) -> Command {
Command(Arc::new(command)) Command(Arc::new(command))
} }

View File

@ -37,22 +37,11 @@ impl WholeStreamCommand for Compact {
} }
fn examples(&self) -> Vec<Example> { fn examples(&self) -> Vec<Example> {
vec![ vec![Example {
Example {
description: "Filter out all null entries in a list",
example: "echo [1 2 $null 3 $null $null] | compact",
result: Some(vec![
UntaggedValue::int(1).into(),
UntaggedValue::int(2).into(),
UntaggedValue::int(3).into(),
]),
},
Example {
description: "Filter out all directory entries having no 'target'", description: "Filter out all directory entries having no 'target'",
example: "ls -la | compact target", example: "ls -la | compact target",
result: None, result: None,
}, }]
]
} }
} }

View File

@ -95,15 +95,7 @@ async fn do_(
block.set_redirect(block_redirection); block.set_redirect(block_redirection);
let result = run_block( let result = run_block(&block, &mut context, input, scope).await;
&block,
&mut context,
input,
&scope.it,
&scope.vars,
&scope.env,
)
.await;
if ignore_errors { if ignore_errors {
// To properly ignore errors we need to redirect stderr, consume it, and remove // To properly ignore errors we need to redirect stderr, consume it, and remove

View File

@ -97,9 +97,7 @@ pub async fn process_row(
&block, &block,
Arc::make_mut(&mut context), Arc::make_mut(&mut context),
input_stream, input_stream,
&input, Scope::append_it(scope, input),
&scope.vars,
&scope.env,
) )
.await? .await?
.to_output_stream()) .to_output_stream())
@ -119,7 +117,7 @@ async fn each(
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
let registry = registry.clone(); let registry = registry.clone();
let head = Arc::new(raw_args.call_info.args.head.clone()); let head = Arc::new(raw_args.call_info.args.head.clone());
let scope = Arc::new(raw_args.call_info.scope.clone()); let scope = raw_args.call_info.scope.clone();
let context = Arc::new(EvaluationContext::from_raw(&raw_args, &registry)); let context = Arc::new(EvaluationContext::from_raw(&raw_args, &registry));
let (each_args, input): (EachArgs, _) = raw_args.process(&registry).await?; let (each_args, input): (EachArgs, _) = raw_args.process(&registry).await?;
let block = Arc::new(each_args.block); let block = Arc::new(each_args.block);

View File

@ -53,7 +53,7 @@ impl WholeStreamCommand for EachGroup {
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
let registry = registry.clone(); let registry = registry.clone();
let head = Arc::new(raw_args.call_info.args.head.clone()); let head = Arc::new(raw_args.call_info.args.head.clone());
let scope = Arc::new(raw_args.call_info.scope.clone()); let scope = raw_args.call_info.scope.clone();
let context = Arc::new(EvaluationContext::from_raw(&raw_args, &registry)); let context = Arc::new(EvaluationContext::from_raw(&raw_args, &registry));
let (each_args, input): (EachGroupArgs, _) = raw_args.process(&registry).await?; let (each_args, input): (EachGroupArgs, _) = raw_args.process(&registry).await?;
let block = Arc::new(each_args.block); let block = Arc::new(each_args.block);

View File

@ -57,7 +57,7 @@ impl WholeStreamCommand for EachWindow {
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
let registry = registry.clone(); let registry = registry.clone();
let head = Arc::new(raw_args.call_info.args.head.clone()); let head = Arc::new(raw_args.call_info.args.head.clone());
let scope = Arc::new(raw_args.call_info.scope.clone()); let scope = raw_args.call_info.scope.clone();
let context = Arc::new(EvaluationContext::from_raw(&raw_args, &registry)); let context = Arc::new(EvaluationContext::from_raw(&raw_args, &registry));
let (each_args, mut input): (EachWindowArgs, _) = raw_args.process(&registry).await?; let (each_args, mut input): (EachWindowArgs, _) = raw_args.process(&registry).await?;
let block = Arc::new(each_args.block); let block = Arc::new(each_args.block);

View File

@ -3,7 +3,7 @@ use crate::commands::WholeStreamCommand;
use crate::evaluate::evaluate_baseline_expr; use crate::evaluate::evaluate_baseline_expr;
use crate::prelude::*; use crate::prelude::*;
use nu_errors::ShellError; use nu_errors::ShellError;
use nu_protocol::{ReturnSuccess, Signature, SyntaxShape, UntaggedValue}; use nu_protocol::{ReturnSuccess, Scope, Signature, SyntaxShape, UntaggedValue};
use nu_source::Tagged; use nu_source::Tagged;
use std::borrow::Borrow; use std::borrow::Borrow;
@ -54,7 +54,7 @@ async fn format_command(
registry: &CommandRegistry, registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
let registry = Arc::new(registry.clone()); let registry = Arc::new(registry.clone());
let scope = Arc::new(args.call_info.scope.clone()); let scope = args.call_info.scope.clone();
let (FormatArgs { pattern }, input) = args.process(&registry).await?; let (FormatArgs { pattern }, input) = args.process(&registry).await?;
let format_pattern = format(&pattern); let format_pattern = format(&pattern);
@ -83,9 +83,7 @@ async fn format_command(
let result = evaluate_baseline_expr( let result = evaluate_baseline_expr(
&full_column_path.0, &full_column_path.0,
&registry, &registry,
&value, Scope::append_it(scope.clone(), value.clone()),
&scope.vars,
&scope.env,
) )
.await; .await;

View File

@ -96,7 +96,7 @@ pub async fn group_by(
let name = args.call_info.name_tag.clone(); let name = args.call_info.name_tag.clone();
let registry = registry.clone(); let registry = registry.clone();
let head = Arc::new(args.call_info.args.head.clone()); let head = Arc::new(args.call_info.args.head.clone());
let scope = Arc::new(args.call_info.scope.clone()); let scope = args.call_info.scope.clone();
let context = Arc::new(EvaluationContext::from_raw(&args, &registry)); let context = Arc::new(EvaluationContext::from_raw(&args, &registry));
let (GroupByArgs { grouper }, input) = args.process(&registry).await?; let (GroupByArgs { grouper }, input) = args.process(&registry).await?;

View File

@ -4,7 +4,9 @@ use crate::commands::WholeStreamCommand;
use crate::evaluate::evaluate_baseline_expr; use crate::evaluate::evaluate_baseline_expr;
use crate::prelude::*; use crate::prelude::*;
use nu_errors::ShellError; use nu_errors::ShellError;
use nu_protocol::{hir::Block, hir::ClassifiedCommand, Signature, SyntaxShape, UntaggedValue}; use nu_protocol::{
hir::Block, hir::ClassifiedCommand, Scope, Signature, SyntaxShape, UntaggedValue,
};
pub struct If; pub struct If;
@ -72,7 +74,7 @@ async fn if_command(
registry: &CommandRegistry, registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
let registry = Arc::new(registry.clone()); let registry = Arc::new(registry.clone());
let scope = Arc::new(raw_args.call_info.scope.clone()); let scope = raw_args.call_info.scope.clone();
let tag = raw_args.call_info.name_tag.clone(); let tag = raw_args.call_info.name_tag.clone();
let context = Arc::new(EvaluationContext::from_raw(&raw_args, &registry)); let context = Arc::new(EvaluationContext::from_raw(&raw_args, &registry));
@ -119,14 +121,12 @@ async fn if_command(
let then_case = then_case.clone(); let then_case = then_case.clone();
let else_case = else_case.clone(); let else_case = else_case.clone();
let registry = registry.clone(); let registry = registry.clone();
let scope = scope.clone(); let scope = Scope::append_it(scope.clone(), input);
let mut context = context.clone(); let mut context = context.clone();
async move { async move {
//FIXME: should we use the scope that's brought in as well? //FIXME: should we use the scope that's brought in as well?
let condition = let condition = evaluate_baseline_expr(&condition, &*registry, scope.clone()).await;
evaluate_baseline_expr(&condition, &*registry, &input, &scope.vars, &scope.env)
.await;
match condition { match condition {
Ok(condition) => match condition.as_bool() { Ok(condition) => match condition.as_bool() {
@ -136,9 +136,7 @@ async fn if_command(
&then_case, &then_case,
Arc::make_mut(&mut context), Arc::make_mut(&mut context),
InputStream::empty(), InputStream::empty(),
&input, scope,
&scope.vars,
&scope.env,
) )
.await .await
{ {
@ -151,9 +149,7 @@ async fn if_command(
&else_case, &else_case,
Arc::make_mut(&mut context), Arc::make_mut(&mut context),
InputStream::empty(), InputStream::empty(),
&input, scope,
&scope.vars,
&scope.env,
) )
.await .await
{ {

View File

@ -63,15 +63,9 @@ async fn process_row(
let for_block = input.clone(); let for_block = input.clone();
let input_stream = once(async { Ok(for_block) }).to_input_stream(); let input_stream = once(async { Ok(for_block) }).to_input_stream();
let result = run_block( let scope = Scope::append_it(scope, input.clone());
&block,
Arc::make_mut(&mut context), let result = run_block(&block, Arc::make_mut(&mut context), input_stream, scope).await;
input_stream,
&input,
&scope.vars,
&scope.env,
)
.await;
match result { match result {
Ok(mut stream) => { Ok(mut stream) => {
@ -118,7 +112,11 @@ async fn process_row(
Value { Value {
value: UntaggedValue::Primitive(Primitive::Nothing), value: UntaggedValue::Primitive(Primitive::Nothing),
.. ..
} => match scope.it.insert_data_at_column_path(&field, value.clone()) { } => match scope
.it()
.unwrap_or_else(|| UntaggedValue::nothing().into_untagged_value())
.insert_data_at_column_path(&field, value.clone())
{
Ok(v) => OutputStream::one(ReturnSuccess::value(v)), Ok(v) => OutputStream::one(ReturnSuccess::value(v)),
Err(e) => OutputStream::one(Err(e)), Err(e) => OutputStream::one(Err(e)),
}, },
@ -135,7 +133,7 @@ async fn insert(
registry: &CommandRegistry, registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
let registry = registry.clone(); let registry = registry.clone();
let scope = Arc::new(raw_args.call_info.scope.clone()); let scope = raw_args.call_info.scope.clone();
let context = Arc::new(EvaluationContext::from_raw(&raw_args, &registry)); let context = Arc::new(EvaluationContext::from_raw(&raw_args, &registry));
let (InsertArgs { column, value }, input) = raw_args.process(&registry).await?; let (InsertArgs { column, value }, input) = raw_args.process(&registry).await?;
let value = Arc::new(value); let value = Arc::new(value);

View File

@ -3,7 +3,7 @@ use crate::evaluate::evaluate_baseline_expr;
use crate::prelude::*; use crate::prelude::*;
use log::trace; use log::trace;
use nu_errors::ShellError; use nu_errors::ShellError;
use nu_protocol::{hir::ClassifiedCommand, Signature, SyntaxShape, UntaggedValue, Value}; use nu_protocol::{hir::ClassifiedCommand, Scope, Signature, SyntaxShape, UntaggedValue, Value};
pub struct SubCommand; pub struct SubCommand;
@ -33,7 +33,7 @@ impl WholeStreamCommand for SubCommand {
registry: &CommandRegistry, registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
let registry = Arc::new(registry.clone()); let registry = Arc::new(registry.clone());
let scope = Arc::new(args.call_info.scope.clone()); let scope = args.call_info.scope.clone();
let call_info = args.evaluate_once(&registry).await?; let call_info = args.evaluate_once(&registry).await?;
@ -85,19 +85,11 @@ impl WholeStreamCommand for SubCommand {
.take_while(move |item| { .take_while(move |item| {
let condition = condition.clone(); let condition = condition.clone();
let registry = registry.clone(); let registry = registry.clone();
let scope = scope.clone(); let scope = Scope::append_it(scope.clone(), item.clone());
let item = item.clone();
trace!("ITEM = {:?}", item); trace!("ITEM = {:?}", item);
async move { async move {
let result = evaluate_baseline_expr( let result = evaluate_baseline_expr(&*condition, &registry, scope).await;
&*condition,
&registry,
&item,
&scope.vars,
&scope.env,
)
.await;
trace!("RESULT = {:?}", result); trace!("RESULT = {:?}", result);
!matches!(result, Ok(ref v) if v.is_true()) !matches!(result, Ok(ref v) if v.is_true())

View File

@ -3,7 +3,7 @@ use crate::evaluate::evaluate_baseline_expr;
use crate::prelude::*; use crate::prelude::*;
use log::trace; use log::trace;
use nu_errors::ShellError; use nu_errors::ShellError;
use nu_protocol::{hir::ClassifiedCommand, Signature, SyntaxShape, UntaggedValue, Value}; use nu_protocol::{hir::ClassifiedCommand, Scope, Signature, SyntaxShape, UntaggedValue, Value};
pub struct SubCommand; pub struct SubCommand;
@ -33,7 +33,7 @@ impl WholeStreamCommand for SubCommand {
registry: &CommandRegistry, registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
let registry = Arc::new(registry.clone()); let registry = Arc::new(registry.clone());
let scope = Arc::new(args.call_info.scope.clone()); let scope = args.call_info.scope.clone();
let call_info = args.evaluate_once(&registry).await?; let call_info = args.evaluate_once(&registry).await?;
let block = call_info.args.expect_nth(0)?.clone(); let block = call_info.args.expect_nth(0)?.clone();
@ -84,20 +84,11 @@ impl WholeStreamCommand for SubCommand {
.take_while(move |item| { .take_while(move |item| {
let condition = condition.clone(); let condition = condition.clone();
let registry = registry.clone(); let registry = registry.clone();
let scope = scope.clone(); let scope = Scope::append_it(scope.clone(), item.clone());
let item = item.clone();
trace!("ITEM = {:?}", item); trace!("ITEM = {:?}", item);
async move { async move {
let result = evaluate_baseline_expr( let result = evaluate_baseline_expr(&*condition, &registry, scope).await;
&*condition,
&registry,
&item,
&scope.vars,
&scope.env,
)
.await;
trace!("RESULT = {:?}", result); trace!("RESULT = {:?}", result);
matches!(result, Ok(ref v) if v.is_true()) matches!(result, Ok(ref v) if v.is_true())

View File

@ -60,16 +60,8 @@ async fn merge(
let (merge_args, input): (MergeArgs, _) = raw_args.process(&registry).await?; let (merge_args, input): (MergeArgs, _) = raw_args.process(&registry).await?;
let block = merge_args.block; let block = merge_args.block;
let table: Option<Vec<Value>> = match run_block( let table: Option<Vec<Value>> =
&block, match run_block(&block, &mut context, InputStream::empty(), scope).await {
&mut context,
InputStream::empty(),
&scope.it,
&scope.vars,
&scope.env,
)
.await
{
Ok(mut stream) => Some(stream.drain_vec().await), Ok(mut stream) => Some(stream.drain_vec().await),
Err(err) => { Err(err) => {
return Err(err); return Err(err);

View File

@ -87,15 +87,9 @@ async fn process_row(
let row_clone = row.clone(); let row_clone = row.clone();
let input_stream = once(async { Ok(row_clone) }).to_input_stream(); let input_stream = once(async { Ok(row_clone) }).to_input_stream();
Ok(run_block( let scope = Scope::append_it(scope, row);
&block,
Arc::make_mut(&mut context), Ok(run_block(&block, Arc::make_mut(&mut context), input_stream, scope).await?)
input_stream,
&row,
&scope.vars,
&scope.env,
)
.await?)
} }
async fn reduce( async fn reduce(
@ -133,7 +127,7 @@ async fn reduce(
.enumerate() .enumerate()
.fold(initial, move |acc, input| { .fold(initial, move |acc, input| {
let block = Arc::clone(&block); let block = Arc::clone(&block);
let mut scope = base_scope.clone(); let scope = base_scope.clone();
let context = Arc::clone(&context); let context = Arc::clone(&context);
let row = each::make_indexed_item(input.0 + ioffset, input.1); let row = each::make_indexed_item(input.0 + ioffset, input.1);
@ -151,8 +145,8 @@ async fn reduce(
UntaggedValue::table(&values).into_untagged_value() UntaggedValue::table(&values).into_untagged_value()
}; };
scope.vars.insert(String::from("$acc"), f); let scope = Scope::append_var(scope, "$acc".into(), f);
process_row(block, Arc::new(scope), context, row).await process_row(block, scope, context, row).await
} }
}) })
.await? .await?
@ -162,7 +156,7 @@ async fn reduce(
Ok(input Ok(input
.fold(initial, move |acc, row| { .fold(initial, move |acc, row| {
let block = Arc::clone(&block); let block = Arc::clone(&block);
let mut scope = base_scope.clone(); let scope = base_scope.clone();
let context = Arc::clone(&context); let context = Arc::clone(&context);
async { async {
@ -179,8 +173,8 @@ async fn reduce(
UntaggedValue::table(&values).into_untagged_value() UntaggedValue::table(&values).into_untagged_value()
}; };
scope.vars.insert(String::from("$acc"), f); let scope = Scope::append_var(scope, "$acc".into(), f);
process_row(block, Arc::new(scope), context, row).await process_row(block, scope, context, row).await
} }
}) })
.await? .await?

View File

@ -4,7 +4,7 @@ use crate::prelude::*;
use derive_new::new; use derive_new::new;
use nu_errors::ShellError; use nu_errors::ShellError;
use nu_protocol::{hir::Block, Signature, SyntaxShape}; use nu_protocol::{hir::Block, Scope, Signature, SyntaxShape};
#[derive(new, Clone)] #[derive(new, Clone)]
pub struct AliasCommand { pub struct AliasCommand {
@ -47,25 +47,20 @@ impl WholeStreamCommand for AliasCommand {
let mut context = EvaluationContext::from_args(&args, &registry); let mut context = EvaluationContext::from_args(&args, &registry);
let input = args.input; let input = args.input;
let mut scope = call_info.scope.clone(); let scope = call_info.scope.clone();
let evaluated = call_info.evaluate(&registry).await?; let evaluated = call_info.evaluate(&registry).await?;
let mut vars = IndexMap::new();
if let Some(positional) = &evaluated.args.positional { if let Some(positional) = &evaluated.args.positional {
for (pos, arg) in positional.iter().enumerate() { for (pos, arg) in positional.iter().enumerate() {
scope vars.insert(alias_command.args[pos].0.to_string(), arg.clone());
.vars
.insert(alias_command.args[pos].0.to_string(), arg.clone());
} }
} }
let scope = Scope::append_vars(scope, vars);
// FIXME: we need to patch up the spans to point at the top-level error // FIXME: we need to patch up the spans to point at the top-level error
Ok(run_block( Ok(run_block(&block, &mut context, input, scope)
&block,
&mut context,
input,
&scope.it,
&scope.vars,
&scope.env,
)
.await? .await?
.to_output_stream()) .to_output_stream())
} }

View File

@ -133,7 +133,7 @@ impl WholeStreamCommand for RunExternalCommand {
command, command,
&mut external_context, &mut external_context,
input, input,
&scope, scope,
external_redirection, external_redirection,
) )
.await; .await;

View File

@ -3,7 +3,7 @@ use crate::evaluate::evaluate_baseline_expr;
use crate::prelude::*; use crate::prelude::*;
use log::trace; use log::trace;
use nu_errors::ShellError; use nu_errors::ShellError;
use nu_protocol::{hir::ClassifiedCommand, Signature, SyntaxShape, UntaggedValue, Value}; use nu_protocol::{hir::ClassifiedCommand, Scope, Signature, SyntaxShape, UntaggedValue, Value};
pub struct SubCommand; pub struct SubCommand;
@ -33,7 +33,7 @@ impl WholeStreamCommand for SubCommand {
registry: &CommandRegistry, registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
let registry = Arc::new(registry.clone()); let registry = Arc::new(registry.clone());
let scope = Arc::new(args.call_info.scope.clone()); let scope = args.call_info.scope.clone();
let call_info = args.evaluate_once(&registry).await?; let call_info = args.evaluate_once(&registry).await?;
let block = call_info.args.expect_nth(0)?.clone(); let block = call_info.args.expect_nth(0)?.clone();
@ -84,19 +84,11 @@ impl WholeStreamCommand for SubCommand {
.skip_while(move |item| { .skip_while(move |item| {
let condition = condition.clone(); let condition = condition.clone();
let registry = registry.clone(); let registry = registry.clone();
let scope = scope.clone(); let scope = Scope::append_it(scope.clone(), item.clone());
let item = item.clone();
trace!("ITEM = {:?}", item); trace!("ITEM = {:?}", item);
async move { async move {
let result = evaluate_baseline_expr( let result = evaluate_baseline_expr(&*condition, &registry, scope).await;
&*condition,
&registry,
&item,
&scope.vars,
&scope.env,
)
.await;
trace!("RESULT = {:?}", result); trace!("RESULT = {:?}", result);
!matches!(result, Ok(ref v) if v.is_true()) !matches!(result, Ok(ref v) if v.is_true())

View File

@ -3,7 +3,7 @@ use crate::evaluate::evaluate_baseline_expr;
use crate::prelude::*; use crate::prelude::*;
use log::trace; use log::trace;
use nu_errors::ShellError; use nu_errors::ShellError;
use nu_protocol::{hir::ClassifiedCommand, Signature, SyntaxShape, UntaggedValue, Value}; use nu_protocol::{hir::ClassifiedCommand, Scope, Signature, SyntaxShape, UntaggedValue, Value};
pub struct SubCommand; pub struct SubCommand;
@ -33,7 +33,7 @@ impl WholeStreamCommand for SubCommand {
registry: &CommandRegistry, registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
let registry = Arc::new(registry.clone()); let registry = Arc::new(registry.clone());
let scope = Arc::new(args.call_info.scope.clone()); let scope = args.call_info.scope.clone();
let call_info = args.evaluate_once(&registry).await?; let call_info = args.evaluate_once(&registry).await?;
let block = call_info.args.expect_nth(0)?.clone(); let block = call_info.args.expect_nth(0)?.clone();
@ -85,18 +85,11 @@ impl WholeStreamCommand for SubCommand {
let item = item.clone(); let item = item.clone();
let condition = condition.clone(); let condition = condition.clone();
let registry = registry.clone(); let registry = registry.clone();
let scope = scope.clone(); let scope = Scope::append_it(scope.clone(), item.clone());
trace!("ITEM = {:?}", item); trace!("ITEM = {:?}", item);
async move { async move {
let result = evaluate_baseline_expr( let result = evaluate_baseline_expr(&*condition, &registry, scope).await;
&*condition,
&registry,
&item,
&scope.vars,
&scope.env,
)
.await;
trace!("RESULT = {:?}", result); trace!("RESULT = {:?}", result);
matches!(result, Ok(ref v) if v.is_true()) matches!(result, Ok(ref v) if v.is_true())

View File

@ -70,15 +70,9 @@ async fn process_row(
let for_block = input.clone(); let for_block = input.clone();
let input_stream = once(async { Ok(for_block) }).to_input_stream(); let input_stream = once(async { Ok(for_block) }).to_input_stream();
let result = run_block( let scope = Scope::append_it(scope, input.clone());
&block,
Arc::make_mut(&mut context), let result = run_block(&block, Arc::make_mut(&mut context), input_stream, scope).await;
input_stream,
&input,
&scope.vars,
&scope.env,
)
.await;
match result { match result {
Ok(mut stream) => { Ok(mut stream) => {
@ -130,7 +124,8 @@ async fn process_row(
value: UntaggedValue::Primitive(Primitive::Nothing), value: UntaggedValue::Primitive(Primitive::Nothing),
.. ..
} => match scope } => match scope
.it .it()
.unwrap_or_else(|| UntaggedValue::nothing().into_untagged_value())
.replace_data_at_column_path(&field, replacement.clone()) .replace_data_at_column_path(&field, replacement.clone())
{ {
Some(v) => OutputStream::one(ReturnSuccess::value(v)), Some(v) => OutputStream::one(ReturnSuccess::value(v)),
@ -160,7 +155,7 @@ async fn update(
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
let registry = registry.clone(); let registry = registry.clone();
let name_tag = Arc::new(raw_args.call_info.name_tag.clone()); let name_tag = Arc::new(raw_args.call_info.name_tag.clone());
let scope = Arc::new(raw_args.call_info.scope.clone()); let scope = raw_args.call_info.scope.clone();
let context = Arc::new(EvaluationContext::from_raw(&raw_args, &registry)); let context = Arc::new(EvaluationContext::from_raw(&raw_args, &registry));
let (UpdateArgs { field, replacement }, input) = raw_args.process(&registry).await?; let (UpdateArgs { field, replacement }, input) = raw_args.process(&registry).await?;
let replacement = Arc::new(replacement); let replacement = Arc::new(replacement);

View File

@ -3,7 +3,9 @@ use crate::commands::WholeStreamCommand;
use crate::evaluate::evaluate_baseline_expr; use crate::evaluate::evaluate_baseline_expr;
use crate::prelude::*; use crate::prelude::*;
use nu_errors::ShellError; use nu_errors::ShellError;
use nu_protocol::{hir::Block, hir::ClassifiedCommand, ReturnSuccess, Signature, SyntaxShape}; use nu_protocol::{
hir::Block, hir::ClassifiedCommand, ReturnSuccess, Scope, Signature, SyntaxShape,
};
pub struct Where; pub struct Where;
@ -68,7 +70,7 @@ async fn where_command(
registry: &CommandRegistry, registry: &CommandRegistry,
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
let registry = Arc::new(registry.clone()); let registry = Arc::new(registry.clone());
let scope = Arc::new(raw_args.call_info.scope.clone()); let scope = raw_args.call_info.scope.clone();
let tag = raw_args.call_info.name_tag.clone(); let tag = raw_args.call_info.name_tag.clone();
let (WhereArgs { block }, input) = raw_args.process(&registry).await?; let (WhereArgs { block }, input) = raw_args.process(&registry).await?;
let condition = { let condition = {
@ -104,13 +106,11 @@ async fn where_command(
.filter_map(move |input| { .filter_map(move |input| {
let condition = condition.clone(); let condition = condition.clone();
let registry = registry.clone(); let registry = registry.clone();
let scope = scope.clone(); let scope = Scope::append_it(scope.clone(), input.clone());
async move { async move {
//FIXME: should we use the scope that's brought in as well? //FIXME: should we use the scope that's brought in as well?
let condition = let condition = evaluate_baseline_expr(&condition, &*registry, scope).await;
evaluate_baseline_expr(&condition, &*registry, &input, &scope.vars, &scope.env)
.await;
match condition { match condition {
Ok(condition) => match condition.as_bool() { Ok(condition) => match condition.as_bool() {

View File

@ -2,7 +2,9 @@ use crate::commands::classified::block::run_block;
use crate::commands::WholeStreamCommand; use crate::commands::WholeStreamCommand;
use crate::prelude::*; use crate::prelude::*;
use nu_errors::ShellError; use nu_errors::ShellError;
use nu_protocol::{hir::Block, Signature, SpannedTypeName, SyntaxShape, UntaggedValue, Value}; use nu_protocol::{
hir::Block, Scope, Signature, SpannedTypeName, SyntaxShape, UntaggedValue, Value,
};
pub struct WithEnv; pub struct WithEnv;
@ -77,23 +79,23 @@ async fn with_env(
let registry = registry.clone(); let registry = registry.clone();
let mut context = EvaluationContext::from_raw(&raw_args, &registry); let mut context = EvaluationContext::from_raw(&raw_args, &registry);
let mut scope = raw_args.call_info.scope.clone(); let scope = raw_args.call_info.scope.clone();
let (WithEnvArgs { variable, block }, input) = raw_args.process(&registry).await?; let (WithEnvArgs { variable, block }, input) = raw_args.process(&registry).await?;
let mut env = IndexMap::new();
match &variable.value { match &variable.value {
UntaggedValue::Table(table) => { UntaggedValue::Table(table) => {
if table.len() == 1 { if table.len() == 1 {
// single row([[X W]; [Y Z]]) // single row([[X W]; [Y Z]])
for (k, v) in table[0].row_entries() { for (k, v) in table[0].row_entries() {
scope.env.insert(k.clone(), v.convert_to_string()); env.insert(k.clone(), v.convert_to_string());
} }
} else { } else {
// primitive values([X Y W Z]) // primitive values([X Y W Z])
for row in table.chunks(2) { for row in table.chunks(2) {
if row.len() == 2 && row[0].is_primitive() && row[1].is_primitive() { if row.len() == 2 && row[0].is_primitive() && row[1].is_primitive() {
scope env.insert(row[0].convert_to_string(), row[1].convert_to_string());
.env
.insert(row[0].convert_to_string(), row[1].convert_to_string());
} }
} }
} }
@ -101,7 +103,7 @@ async fn with_env(
// when get object by `open x.json` or `from json` // when get object by `open x.json` or `from json`
UntaggedValue::Row(row) => { UntaggedValue::Row(row) => {
for (k, v) in &row.entries { for (k, v) in &row.entries {
scope.env.insert(k.clone(), v.convert_to_string()); env.insert(k.clone(), v.convert_to_string());
} }
} }
_ => { _ => {
@ -112,15 +114,9 @@ async fn with_env(
} }
}; };
let result = run_block( let scope = Scope::append_env(scope, env);
&block,
&mut context, let result = run_block(&block, &mut context, input, scope).await;
input,
&scope.it,
&scope.vars,
&scope.env,
)
.await;
result.map(|x| x.to_output_stream()) result.map(|x| x.to_output_stream())
} }

View File

@ -4,18 +4,18 @@ use crate::evaluate::evaluate_baseline_expr;
use indexmap::IndexMap; use indexmap::IndexMap;
use nu_errors::ShellError; use nu_errors::ShellError;
use nu_protocol::{hir, EvaluatedArgs, Scope, UntaggedValue, Value}; use nu_protocol::{hir, EvaluatedArgs, Scope, UntaggedValue, Value};
use std::sync::Arc;
pub(crate) async fn evaluate_args( pub(crate) async fn evaluate_args(
call: &hir::Call, call: &hir::Call,
registry: &CommandRegistry, registry: &CommandRegistry,
scope: &Scope, scope: Arc<Scope>,
) -> Result<EvaluatedArgs, ShellError> { ) -> Result<EvaluatedArgs, ShellError> {
let mut positional_args: Vec<Value> = vec![]; let mut positional_args: Vec<Value> = vec![];
if let Some(positional) = &call.positional { if let Some(positional) = &call.positional {
for pos in positional { for pos in positional {
let result = let result = evaluate_baseline_expr(pos, registry, scope.clone()).await?;
evaluate_baseline_expr(pos, registry, &scope.it, &scope.vars, &scope.env).await?;
positional_args.push(result); positional_args.push(result);
} }
} }
@ -37,8 +37,7 @@ pub(crate) async fn evaluate_args(
hir::NamedValue::Value(_, expr) => { hir::NamedValue::Value(_, expr) => {
named_args.insert( named_args.insert(
name.clone(), name.clone(),
evaluate_baseline_expr(expr, registry, &scope.it, &scope.vars, &scope.env) evaluate_baseline_expr(expr, registry, scope.clone()).await?,
.await?,
); );
} }
_ => {} _ => {}

View File

@ -7,16 +7,14 @@ use log::trace;
use nu_errors::{ArgumentError, ShellError}; use nu_errors::{ArgumentError, ShellError};
use nu_protocol::hir::{self, Expression, ExternalRedirection, RangeOperator, SpannedExpression}; use nu_protocol::hir::{self, Expression, ExternalRedirection, RangeOperator, SpannedExpression};
use nu_protocol::{ use nu_protocol::{
ColumnPath, Primitive, RangeInclusion, UnspannedPathMember, UntaggedValue, Value, ColumnPath, Primitive, RangeInclusion, Scope, UnspannedPathMember, UntaggedValue, Value,
}; };
#[async_recursion] #[async_recursion]
pub(crate) async fn evaluate_baseline_expr( pub(crate) async fn evaluate_baseline_expr(
expr: &SpannedExpression, expr: &SpannedExpression,
registry: &CommandRegistry, registry: &CommandRegistry,
it: &Value, scope: Arc<Scope>,
vars: &IndexMap<String, Value>,
env: &IndexMap<String, String>,
) -> Result<Value, ShellError> { ) -> Result<Value, ShellError> {
let tag = Tag { let tag = Tag {
span: expr.span, span: expr.span,
@ -33,14 +31,14 @@ pub(crate) async fn evaluate_baseline_expr(
Expression::Synthetic(hir::Synthetic::String(s)) => { Expression::Synthetic(hir::Synthetic::String(s)) => {
Ok(UntaggedValue::string(s).into_untagged_value()) Ok(UntaggedValue::string(s).into_untagged_value())
} }
Expression::Variable(var) => evaluate_reference(&var, it, vars, env, tag), Expression::Variable(var) => evaluate_reference(&var, scope, tag),
Expression::Command => unimplemented!(), Expression::Command => unimplemented!(),
Expression::Invocation(block) => evaluate_invocation(block, registry, it, vars, env).await, Expression::Invocation(block) => evaluate_invocation(block, registry, scope).await,
Expression::ExternalCommand(_) => unimplemented!(), Expression::ExternalCommand(_) => unimplemented!(),
Expression::Binary(binary) => { Expression::Binary(binary) => {
// TODO: If we want to add short-circuiting, we'll need to move these down // TODO: If we want to add short-circuiting, we'll need to move these down
let left = evaluate_baseline_expr(&binary.left, registry, it, vars, env).await?; let left = evaluate_baseline_expr(&binary.left, registry, scope.clone()).await?;
let right = evaluate_baseline_expr(&binary.right, registry, it, vars, env).await?; let right = evaluate_baseline_expr(&binary.right, registry, scope).await?;
trace!("left={:?} right={:?}", left.value, right.value); trace!("left={:?} right={:?}", left.value, right.value);
@ -62,13 +60,13 @@ pub(crate) async fn evaluate_baseline_expr(
} }
Expression::Range(range) => { Expression::Range(range) => {
let left = if let Some(left) = &range.left { let left = if let Some(left) = &range.left {
evaluate_baseline_expr(&left, registry, it, vars, env).await? evaluate_baseline_expr(&left, registry, scope.clone()).await?
} else { } else {
Value::nothing() Value::nothing()
}; };
let right = if let Some(right) = &range.right { let right = if let Some(right) = &range.right {
evaluate_baseline_expr(&right, registry, it, vars, env).await? evaluate_baseline_expr(&right, registry, scope).await?
} else { } else {
Value::nothing() Value::nothing()
}; };
@ -94,7 +92,7 @@ pub(crate) async fn evaluate_baseline_expr(
let mut output_headers = vec![]; let mut output_headers = vec![];
for expr in headers { for expr in headers {
let val = evaluate_baseline_expr(&expr, registry, it, vars, env).await?; let val = evaluate_baseline_expr(&expr, registry, scope.clone()).await?;
let header = val.as_string()?; let header = val.as_string()?;
output_headers.push(header); output_headers.push(header);
@ -122,7 +120,7 @@ pub(crate) async fn evaluate_baseline_expr(
let mut row_output = IndexMap::new(); let mut row_output = IndexMap::new();
for cell in output_headers.iter().zip(row.iter()) { for cell in output_headers.iter().zip(row.iter()) {
let val = evaluate_baseline_expr(&cell.1, registry, it, vars, env).await?; let val = evaluate_baseline_expr(&cell.1, registry, scope.clone()).await?;
row_output.insert(cell.0.clone(), val); row_output.insert(cell.0.clone(), val);
} }
output_table.push(UntaggedValue::row(row_output).into_value(tag.clone())); output_table.push(UntaggedValue::row(row_output).into_value(tag.clone()));
@ -134,7 +132,7 @@ pub(crate) async fn evaluate_baseline_expr(
let mut exprs = vec![]; let mut exprs = vec![];
for expr in list { for expr in list {
let expr = evaluate_baseline_expr(&expr, registry, it, vars, env).await?; let expr = evaluate_baseline_expr(&expr, registry, scope.clone()).await?;
exprs.push(expr); exprs.push(expr);
} }
@ -142,7 +140,7 @@ pub(crate) async fn evaluate_baseline_expr(
} }
Expression::Block(block) => Ok(UntaggedValue::Block(block.clone()).into_value(&tag)), Expression::Block(block) => Ok(UntaggedValue::Block(block.clone()).into_value(&tag)),
Expression::Path(path) => { Expression::Path(path) => {
let value = evaluate_baseline_expr(&path.head, registry, it, vars, env).await?; let value = evaluate_baseline_expr(&path.head, registry, scope).await?;
let mut item = value; let mut item = value;
for member in &path.tail { for member in &path.tail {
@ -208,15 +206,20 @@ fn evaluate_literal(literal: &hir::Literal, span: Span) -> Value {
fn evaluate_reference( fn evaluate_reference(
name: &hir::Variable, name: &hir::Variable,
it: &Value, scope: Arc<Scope>,
vars: &IndexMap<String, Value>,
env: &IndexMap<String, String>,
tag: Tag, tag: Tag,
) -> Result<Value, ShellError> { ) -> Result<Value, ShellError> {
match name { match name {
hir::Variable::It(_) => Ok(it.clone()), hir::Variable::It(_) => match scope.it() {
Some(v) => Ok(v),
None => Err(ShellError::labeled_error(
"$it variable not in scope",
"not in scope (are you missing an 'each'?)",
tag.span,
)),
},
hir::Variable::Other(name, _) => match name { hir::Variable::Other(name, _) => match name {
x if x == "$nu" => crate::evaluate::variables::nu(env, tag), x if x == "$nu" => crate::evaluate::variables::nu(&scope.env(), tag),
x if x == "$true" => Ok(Value { x if x == "$true" => Ok(Value {
value: UntaggedValue::boolean(true), value: UntaggedValue::boolean(true),
tag, tag,
@ -225,10 +228,14 @@ fn evaluate_reference(
value: UntaggedValue::boolean(false), value: UntaggedValue::boolean(false),
tag, tag,
}), }),
x => Ok(vars x => match scope.var(x) {
.get(x) Some(v) => Ok(v),
.cloned() None => Err(ShellError::labeled_error(
.unwrap_or_else(|| UntaggedValue::nothing().into_value(tag))), "Variable not in scope",
"unknown variable",
tag.span,
)),
},
}, },
} }
} }
@ -236,20 +243,21 @@ fn evaluate_reference(
async fn evaluate_invocation( async fn evaluate_invocation(
block: &hir::Block, block: &hir::Block,
registry: &CommandRegistry, registry: &CommandRegistry,
it: &Value, scope: Arc<Scope>,
vars: &IndexMap<String, Value>,
env: &IndexMap<String, String>,
) -> Result<Value, ShellError> { ) -> Result<Value, ShellError> {
// FIXME: we should use a real context here // FIXME: we should use a real context here
let mut context = EvaluationContext::basic()?; let mut context = EvaluationContext::basic()?;
context.registry = registry.clone(); context.registry = registry.clone();
let input = InputStream::one(it.clone()); let input = match scope.it() {
Some(it) => InputStream::one(it),
None => InputStream::empty(),
};
let mut block = block.clone(); let mut block = block.clone();
block.set_redirect(ExternalRedirection::Stdout); block.set_redirect(ExternalRedirection::Stdout);
let result = run_block(&block, &mut context, input, it, vars, env).await?; let result = run_block(&block, &mut context, input, scope).await?;
let output = result.into_vec().await; let output = result.into_vec().await;

View File

@ -152,18 +152,18 @@ impl EvaluationContext {
command: Command, command: Command,
name_tag: Tag, name_tag: Tag,
args: hir::Call, args: hir::Call,
scope: &Scope, scope: Arc<Scope>,
input: InputStream, input: InputStream,
) -> Result<OutputStream, ShellError> { ) -> Result<OutputStream, ShellError> {
let command_args = self.command_args(args, input, name_tag, scope); let command_args = self.command_args(args, input, name_tag, scope);
command.run(command_args, self.registry()).await command.run(command_args, self.registry()).await
} }
fn call_info(&self, args: hir::Call, name_tag: Tag, scope: &Scope) -> UnevaluatedCallInfo { fn call_info(&self, args: hir::Call, name_tag: Tag, scope: Arc<Scope>) -> UnevaluatedCallInfo {
UnevaluatedCallInfo { UnevaluatedCallInfo {
args, args,
name_tag, name_tag,
scope: scope.clone(), scope,
} }
} }
@ -172,7 +172,7 @@ impl EvaluationContext {
args: hir::Call, args: hir::Call,
input: InputStream, input: InputStream,
name_tag: Tag, name_tag: Tag,
scope: &Scope, scope: Arc<Scope>,
) -> CommandArgs { ) -> CommandArgs {
CommandArgs { CommandArgs {
host: self.host.clone(), host: self.host.clone(),

View File

@ -1,9 +1,8 @@
use futures::executor::block_on; use futures::executor::block_on;
use crate::prelude::*;
use nu_errors::ShellError; use nu_errors::ShellError;
use nu_protocol::hir::ClassifiedBlock; use nu_protocol::hir::ClassifiedBlock;
use nu_protocol::{ShellTypeName, Value}; use nu_protocol::{Scope, ShellTypeName, Value};
use crate::commands::classified::block::run_block; use crate::commands::classified::block::run_block;
use crate::commands::{whole_stream_command, BuildString, Each, Echo, StrCollect}; use crate::commands::{whole_stream_command, BuildString, Each, Echo, StrCollect};
@ -83,14 +82,9 @@ async fn evaluate_block(
let input_stream = InputStream::empty(); let input_stream = InputStream::empty();
let env = ctx.get_env(); let env = ctx.get_env();
Ok(run_block( let scope = Scope::from_env(env);
&block.block,
ctx, Ok(run_block(&block.block, ctx, input_stream, scope)
input_stream,
&Value::nothing(),
&IndexMap::new(),
&env,
)
.await? .await?
.into_vec() .into_vec()
.await) .await)

View File

@ -2,30 +2,121 @@ use crate::value::Value;
use indexmap::IndexMap; use indexmap::IndexMap;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::fmt::Debug; use std::fmt::Debug;
use std::sync::Arc;
/// An evaluation scope. Scopes map variable names to Values and aid in evaluating blocks and expressions. /// An evaluation scope. Scopes map variable names to Values and aid in evaluating blocks and expressions.
/// Additionally, holds the value for the special $it variable, a variable used to refer to the value passing /// Additionally, holds the value for the special $it variable, a variable used to refer to the value passing
/// through the pipeline at that moment /// through the pipeline at that moment
#[derive(Deserialize, Serialize, Debug, Clone)] #[derive(Deserialize, Serialize, Debug, Clone)]
pub struct Scope { pub struct Scope {
pub it: Value, vars: IndexMap<String, Value>,
pub vars: IndexMap<String, Value>, env: IndexMap<String, String>,
pub env: IndexMap<String, String>, parent: Option<Arc<Scope>>,
} }
impl Scope { impl Scope {
pub fn vars(&self) -> IndexMap<String, Value> {
//FIXME: should this be an interator?
let mut output = IndexMap::new();
for v in &self.vars {
output.insert(v.0.clone(), v.1.clone());
}
if let Some(parent) = &self.parent {
for v in parent.vars() {
if !output.contains_key(&v.0) {
output.insert(v.0.clone(), v.1.clone());
}
}
}
output
}
pub fn env(&self) -> IndexMap<String, String> {
//FIXME: should this be an interator?
let mut output = IndexMap::new();
for v in &self.env {
output.insert(v.0.clone(), v.1.clone());
}
if let Some(parent) = &self.parent {
for v in parent.env() {
if !output.contains_key(&v.0) {
output.insert(v.0.clone(), v.1.clone());
}
}
}
output
}
pub fn var(&self, name: &str) -> Option<Value> {
if let Some(value) = self.vars().get(name) {
Some(value.clone())
} else {
None
}
}
pub fn it(&self) -> Option<Value> {
self.var("$it")
}
pub fn from_env(env: IndexMap<String, String>) -> Arc<Scope> {
Arc::new(Scope {
vars: IndexMap::new(),
env,
parent: None,
})
}
pub fn append_it(this: Arc<Self>, it: Value) -> Arc<Scope> {
let mut vars = IndexMap::new();
vars.insert("$it".into(), it);
Arc::new(Scope {
vars,
env: IndexMap::new(),
parent: Some(this),
})
}
pub fn append_var(this: Arc<Self>, name: String, value: Value) -> Arc<Scope> {
let mut vars = IndexMap::new();
vars.insert(name, value);
Arc::new(Scope {
vars,
env: IndexMap::new(),
parent: Some(this),
})
}
pub fn append_vars(this: Arc<Self>, vars: IndexMap<String, Value>) -> Arc<Scope> {
Arc::new(Scope {
vars,
env: IndexMap::new(),
parent: Some(this),
})
}
pub fn append_env(this: Arc<Self>, env: IndexMap<String, String>) -> Arc<Scope> {
Arc::new(Scope {
vars: IndexMap::new(),
env,
parent: Some(this),
})
}
/// Create an empty scope /// Create an empty scope
pub fn new() -> Scope { pub fn create() -> Arc<Scope> {
Scope { Arc::new(Scope {
it: Value::nothing(),
vars: IndexMap::new(), vars: IndexMap::new(),
env: IndexMap::new(), env: IndexMap::new(),
} parent: None,
} })
}
impl Default for Scope {
fn default() -> Scope {
Scope::new()
} }
} }