mirror of
https://github.com/nushell/nushell.git
synced 2024-11-22 16:33:37 +01:00
Track call arguments in a single list (#5125)
* Initial implementation of ordered call args * Run cargo fmt * Fix some clippy lints * Add positional len and nth * Cargo fmt * Remove more old nth calls * Good ole rustfmt * Add named len Co-authored-by: Hristo Filaretov <h.filaretov@protonmail.com>
This commit is contained in:
parent
3bac480ca0
commit
683b912263
@ -1,7 +1,7 @@
|
|||||||
use crate::completions::{Completer, CompletionOptions, SortBy};
|
use crate::completions::{Completer, CompletionOptions, SortBy};
|
||||||
use nu_engine::eval_call;
|
use nu_engine::eval_call;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::{Call, Expr, Expression},
|
ast::{Argument, Call, Expr, Expression},
|
||||||
engine::{EngineState, Stack, StateWorkingSet},
|
engine::{EngineState, Stack, StateWorkingSet},
|
||||||
PipelineData, Span, Type, Value, CONFIG_VARIABLE_ID,
|
PipelineData, Span, Type, Value, CONFIG_VARIABLE_ID,
|
||||||
};
|
};
|
||||||
@ -92,21 +92,20 @@ impl Completer for CustomCompletion {
|
|||||||
&Call {
|
&Call {
|
||||||
decl_id: self.decl_id,
|
decl_id: self.decl_id,
|
||||||
head: span,
|
head: span,
|
||||||
positional: vec![
|
arguments: vec![
|
||||||
Expression {
|
Argument::Positional(Expression {
|
||||||
span: Span { start: 0, end: 0 },
|
span: Span { start: 0, end: 0 },
|
||||||
ty: Type::String,
|
ty: Type::String,
|
||||||
expr: Expr::String(self.line.clone()),
|
expr: Expr::String(self.line.clone()),
|
||||||
custom_completion: None,
|
custom_completion: None,
|
||||||
},
|
}),
|
||||||
Expression {
|
Argument::Positional(Expression {
|
||||||
span: Span { start: 0, end: 0 },
|
span: Span { start: 0, end: 0 },
|
||||||
ty: Type::Int,
|
ty: Type::Int,
|
||||||
expr: Expr::Int(line_pos as i64),
|
expr: Expr::Int(line_pos as i64),
|
||||||
custom_completion: None,
|
custom_completion: None,
|
||||||
},
|
}),
|
||||||
],
|
],
|
||||||
named: vec![],
|
|
||||||
redirect_stdout: true,
|
redirect_stdout: true,
|
||||||
redirect_stderr: true,
|
redirect_stderr: true,
|
||||||
},
|
},
|
||||||
|
@ -61,11 +61,15 @@ https://www.nushell.sh/book/thinking_in_nushell.html#parsing-and-evaluation-are-
|
|||||||
_input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
let head = call.head;
|
let head = call.head;
|
||||||
let var_id = call.positional[0]
|
let var_id = call
|
||||||
|
.positional_nth(0)
|
||||||
|
.expect("checked through parser")
|
||||||
.as_var()
|
.as_var()
|
||||||
.expect("internal error: missing variable");
|
.expect("internal error: missing variable");
|
||||||
|
|
||||||
let keyword_expr = call.positional[1]
|
let keyword_expr = call
|
||||||
|
.positional_nth(1)
|
||||||
|
.expect("checked through parser")
|
||||||
.as_keyword()
|
.as_keyword()
|
||||||
.expect("internal error: missing keyword");
|
.expect("internal error: missing keyword");
|
||||||
let values = eval_expression(engine_state, stack, keyword_expr)?;
|
let values = eval_expression(engine_state, stack, keyword_expr)?;
|
||||||
|
@ -44,7 +44,7 @@ https://www.nushell.sh/book/thinking_in_nushell.html#parsing-and-evaluation-are-
|
|||||||
let import_pattern = if let Some(Expression {
|
let import_pattern = if let Some(Expression {
|
||||||
expr: Expr::ImportPattern(pat),
|
expr: Expr::ImportPattern(pat),
|
||||||
..
|
..
|
||||||
}) = call.positional.get(0)
|
}) = call.positional_nth(0)
|
||||||
{
|
{
|
||||||
pat
|
pat
|
||||||
} else {
|
} else {
|
||||||
@ -115,7 +115,11 @@ https://www.nushell.sh/book/thinking_in_nushell.html#parsing-and-evaluation-are-
|
|||||||
};
|
};
|
||||||
|
|
||||||
if stack.remove_env_var(engine_state, &name).is_none() {
|
if stack.remove_env_var(engine_state, &name).is_none() {
|
||||||
return Err(ShellError::NotFound(call.positional[0].span));
|
return Err(ShellError::NotFound(
|
||||||
|
call.positional_nth(0)
|
||||||
|
.expect("already checked for present positional")
|
||||||
|
.span,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if !import_pattern.hidden.contains(&import_pattern.head.name)
|
} else if !import_pattern.hidden.contains(&import_pattern.head.name)
|
||||||
|
@ -50,9 +50,9 @@ https://www.nushell.sh/book/thinking_in_nushell.html#parsing-and-evaluation-are-
|
|||||||
call: &Call,
|
call: &Call,
|
||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
let cond = &call.positional[0];
|
let cond = call.positional_nth(0).expect("checked through parser");
|
||||||
let then_block: CaptureBlock = call.req(engine_state, stack, 1)?;
|
let then_block: CaptureBlock = call.req(engine_state, stack, 1)?;
|
||||||
let else_case = call.positional.get(2);
|
let else_case = call.positional_nth(2);
|
||||||
|
|
||||||
let result = eval_expression(engine_state, stack, cond)?;
|
let result = eval_expression(engine_state, stack, cond)?;
|
||||||
match &result {
|
match &result {
|
||||||
|
@ -42,11 +42,15 @@ https://www.nushell.sh/book/thinking_in_nushell.html#parsing-and-evaluation-are-
|
|||||||
call: &Call,
|
call: &Call,
|
||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
let var_id = call.positional[0]
|
let var_id = call
|
||||||
|
.positional_nth(0)
|
||||||
|
.expect("checked through parser")
|
||||||
.as_var()
|
.as_var()
|
||||||
.expect("internal error: missing variable");
|
.expect("internal error: missing variable");
|
||||||
|
|
||||||
let keyword_expr = call.positional[1]
|
let keyword_expr = call
|
||||||
|
.positional_nth(1)
|
||||||
|
.expect("checked through parser")
|
||||||
.as_keyword()
|
.as_keyword()
|
||||||
.expect("internal error: missing keyword");
|
.expect("internal error: missing keyword");
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ impl Command for Metadata {
|
|||||||
call: &Call,
|
call: &Call,
|
||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
let arg = call.positional.get(0);
|
let arg = call.positional_nth(0);
|
||||||
let head = call.head;
|
let head = call.head;
|
||||||
|
|
||||||
match arg {
|
match arg {
|
||||||
|
@ -42,7 +42,7 @@ https://www.nushell.sh/book/thinking_in_nushell.html#parsing-and-evaluation-are-
|
|||||||
let import_pattern = if let Some(Expression {
|
let import_pattern = if let Some(Expression {
|
||||||
expr: Expr::ImportPattern(pat),
|
expr: Expr::ImportPattern(pat),
|
||||||
..
|
..
|
||||||
}) = call.positional.get(0)
|
}) = call.positional_nth(0)
|
||||||
{
|
{
|
||||||
pat
|
pat
|
||||||
} else {
|
} else {
|
||||||
|
4
crates/nu-command/src/env/let_env.rs
vendored
4
crates/nu-command/src/env/let_env.rs
vendored
@ -35,7 +35,9 @@ impl Command for LetEnv {
|
|||||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
let env_var = call.req(engine_state, stack, 0)?;
|
let env_var = call.req(engine_state, stack, 0)?;
|
||||||
|
|
||||||
let keyword_expr = call.positional[1]
|
let keyword_expr = call
|
||||||
|
.positional_nth(1)
|
||||||
|
.expect("checked through parser")
|
||||||
.as_keyword()
|
.as_keyword()
|
||||||
.expect("internal error: missing keyword");
|
.expect("internal error: missing keyword");
|
||||||
|
|
||||||
|
8
crates/nu-command/src/env/with_env.rs
vendored
8
crates/nu-command/src/env/with_env.rs
vendored
@ -99,7 +99,9 @@ fn with_env(
|
|||||||
return Err(ShellError::CantConvert(
|
return Err(ShellError::CantConvert(
|
||||||
"string list or single row".into(),
|
"string list or single row".into(),
|
||||||
x.get_type().to_string(),
|
x.get_type().to_string(),
|
||||||
call.positional[1].span,
|
call.positional_nth(1)
|
||||||
|
.expect("already checked through .req")
|
||||||
|
.span,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -123,7 +125,9 @@ fn with_env(
|
|||||||
return Err(ShellError::CantConvert(
|
return Err(ShellError::CantConvert(
|
||||||
"string list or single row".into(),
|
"string list or single row".into(),
|
||||||
x.get_type().to_string(),
|
x.get_type().to_string(),
|
||||||
call.positional[1].span,
|
call.positional_nth(1)
|
||||||
|
.expect("already checked through .req")
|
||||||
|
.span,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -28,7 +28,7 @@ impl Command for Cd {
|
|||||||
call: &Call,
|
call: &Call,
|
||||||
_input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
let raw_path = call.nth(0);
|
let raw_path = call.positional_nth(0);
|
||||||
let path_val: Option<Value> = call.opt(engine_state, stack, 0)?;
|
let path_val: Option<Value> = call.opt(engine_state, stack, 0)?;
|
||||||
let cwd = current_dir(engine_state, stack)?;
|
let cwd = current_dir(engine_state, stack)?;
|
||||||
|
|
||||||
|
@ -57,13 +57,18 @@ impl Command for Mkdir {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (i, dir) in directories.enumerate() {
|
for (i, dir) in directories.enumerate() {
|
||||||
let span = call.positional[i].span;
|
let span = call
|
||||||
|
.positional_nth(i)
|
||||||
|
.expect("already checked through directories")
|
||||||
|
.span;
|
||||||
let dir_res = std::fs::create_dir_all(&dir);
|
let dir_res = std::fs::create_dir_all(&dir);
|
||||||
|
|
||||||
if let Err(reason) = dir_res {
|
if let Err(reason) = dir_res {
|
||||||
return Err(ShellError::CreateNotPossible(
|
return Err(ShellError::CreateNotPossible(
|
||||||
format!("failed to create directory: {}", reason),
|
format!("failed to create directory: {}", reason),
|
||||||
call.positional[i].span,
|
call.positional_nth(i)
|
||||||
|
.expect("already checked through directories")
|
||||||
|
.span,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,7 +239,9 @@ impl Command for Touch {
|
|||||||
if let Err(err) = OpenOptions::new().write(true).create(true).open(&item) {
|
if let Err(err) = OpenOptions::new().write(true).create(true).open(&item) {
|
||||||
return Err(ShellError::CreateNotPossible(
|
return Err(ShellError::CreateNotPossible(
|
||||||
format!("Failed to create file: {}", err),
|
format!("Failed to create file: {}", err),
|
||||||
call.positional[index].span,
|
call.positional_nth(index)
|
||||||
|
.expect("already checked positional")
|
||||||
|
.span,
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -251,7 +253,9 @@ impl Command for Touch {
|
|||||||
) {
|
) {
|
||||||
return Err(ShellError::ChangeModifiedTimeNotPossible(
|
return Err(ShellError::ChangeModifiedTimeNotPossible(
|
||||||
format!("Failed to change the modified time: {}", err),
|
format!("Failed to change the modified time: {}", err),
|
||||||
call.positional[index].span,
|
call.positional_nth(index)
|
||||||
|
.expect("already checked positional")
|
||||||
|
.span,
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -268,7 +272,9 @@ impl Command for Touch {
|
|||||||
) {
|
) {
|
||||||
return Err(ShellError::ChangeAccessTimeNotPossible(
|
return Err(ShellError::ChangeAccessTimeNotPossible(
|
||||||
format!("Failed to change the access time: {}", err),
|
format!("Failed to change the access time: {}", err),
|
||||||
call.positional[index].span,
|
call.positional_nth(index)
|
||||||
|
.expect("already checked positional")
|
||||||
|
.span,
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
@ -279,7 +285,9 @@ impl Command for Touch {
|
|||||||
) {
|
) {
|
||||||
return Err(ShellError::ChangeAccessTimeNotPossible(
|
return Err(ShellError::ChangeAccessTimeNotPossible(
|
||||||
format!("Failed to change the access time: {}", err),
|
format!("Failed to change the access time: {}", err),
|
||||||
call.positional[index].span,
|
call.positional_nth(index)
|
||||||
|
.expect("already checked positional")
|
||||||
|
.span,
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -380,7 +380,9 @@ Format: #
|
|||||||
None => {
|
None => {
|
||||||
return Err(ShellError::UnsupportedInput(
|
return Err(ShellError::UnsupportedInput(
|
||||||
String::from("Unknown ansi code"),
|
String::from("Unknown ansi code"),
|
||||||
call.nth(0).expect("Unexpected missing argument").span,
|
call.positional_nth(0)
|
||||||
|
.expect("Unexpected missing argument")
|
||||||
|
.span,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,15 +57,14 @@ impl Command for KeybindingsList {
|
|||||||
call: &Call,
|
call: &Call,
|
||||||
_input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
let records = if call.named.is_empty() {
|
let records = if call.named_len() == 0 {
|
||||||
let all_options = vec!["modifiers", "keycodes", "edits", "modes", "events"];
|
let all_options = vec!["modifiers", "keycodes", "edits", "modes", "events"];
|
||||||
all_options
|
all_options
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|argument| get_records(argument, &call.head))
|
.flat_map(|argument| get_records(argument, &call.head))
|
||||||
.collect()
|
.collect()
|
||||||
} else {
|
} else {
|
||||||
call.named
|
call.named_iter()
|
||||||
.iter()
|
|
||||||
.flat_map(|(argument, _)| get_records(argument.item.as_str(), &call.head))
|
.flat_map(|(argument, _)| get_records(argument.item.as_str(), &call.head))
|
||||||
.collect()
|
.collect()
|
||||||
};
|
};
|
||||||
|
@ -54,8 +54,7 @@ impl Command for BuildString {
|
|||||||
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
) -> Result<nu_protocol::PipelineData, nu_protocol::ShellError> {
|
||||||
let config = stack.get_config().unwrap_or_default();
|
let config = stack.get_config().unwrap_or_default();
|
||||||
let output = call
|
let output = call
|
||||||
.positional
|
.positional_iter()
|
||||||
.iter()
|
|
||||||
.map(|expr| {
|
.map(|expr| {
|
||||||
eval_expression(engine_state, stack, expr).map(|val| val.into_string(", ", &config))
|
eval_expression(engine_state, stack, expr).map(|val| val.into_string(", ", &config))
|
||||||
})
|
})
|
||||||
|
@ -245,7 +245,10 @@ impl Command for Char {
|
|||||||
}
|
}
|
||||||
let mut multi_byte = String::new();
|
let mut multi_byte = String::new();
|
||||||
for (i, arg) in args.iter().enumerate() {
|
for (i, arg) in args.iter().enumerate() {
|
||||||
let span = call.nth(i).expect("Unexpected missing argument").span;
|
let span = call
|
||||||
|
.positional_nth(i)
|
||||||
|
.expect("Unexpected missing argument")
|
||||||
|
.span;
|
||||||
multi_byte.push(string_to_unicode_char(arg, &span)?)
|
multi_byte.push(string_to_unicode_char(arg, &span)?)
|
||||||
}
|
}
|
||||||
Ok(Value::string(multi_byte, call_span).into_pipeline_data())
|
Ok(Value::string(multi_byte, call_span).into_pipeline_data())
|
||||||
@ -262,7 +265,9 @@ impl Command for Char {
|
|||||||
} else {
|
} else {
|
||||||
Err(ShellError::UnsupportedInput(
|
Err(ShellError::UnsupportedInput(
|
||||||
"error finding named character".into(),
|
"error finding named character".into(),
|
||||||
call.nth(0).expect("Unexpected missing argument").span,
|
call.positional_nth(0)
|
||||||
|
.expect("Unexpected missing argument")
|
||||||
|
.span,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ impl CallExt for Call {
|
|||||||
) -> Result<Vec<T>, ShellError> {
|
) -> Result<Vec<T>, ShellError> {
|
||||||
let mut output = vec![];
|
let mut output = vec![];
|
||||||
|
|
||||||
for expr in self.positional.iter().skip(starting_pos) {
|
for expr in self.positional_iter().skip(starting_pos) {
|
||||||
let result = eval_expression(engine_state, stack, expr)?;
|
let result = eval_expression(engine_state, stack, expr)?;
|
||||||
output.push(FromValue::from_value(&result)?);
|
output.push(FromValue::from_value(&result)?);
|
||||||
}
|
}
|
||||||
@ -73,8 +73,8 @@ impl CallExt for Call {
|
|||||||
stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
pos: usize,
|
pos: usize,
|
||||||
) -> Result<Option<T>, ShellError> {
|
) -> Result<Option<T>, ShellError> {
|
||||||
if let Some(expr) = self.nth(pos) {
|
if let Some(expr) = self.positional_nth(pos) {
|
||||||
let result = eval_expression(engine_state, stack, &expr)?;
|
let result = eval_expression(engine_state, stack, expr)?;
|
||||||
FromValue::from_value(&result).map(Some)
|
FromValue::from_value(&result).map(Some)
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
@ -87,12 +87,12 @@ impl CallExt for Call {
|
|||||||
stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
pos: usize,
|
pos: usize,
|
||||||
) -> Result<T, ShellError> {
|
) -> Result<T, ShellError> {
|
||||||
if let Some(expr) = self.nth(pos) {
|
if let Some(expr) = self.positional_nth(pos) {
|
||||||
let result = eval_expression(engine_state, stack, &expr)?;
|
let result = eval_expression(engine_state, stack, expr)?;
|
||||||
FromValue::from_value(&result)
|
FromValue::from_value(&result)
|
||||||
} else {
|
} else {
|
||||||
Err(ShellError::AccessBeyondEnd(
|
Err(ShellError::AccessBeyondEnd(
|
||||||
self.positional.len(),
|
self.positional_len(),
|
||||||
self.head,
|
self.head,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ pub fn eval_call(
|
|||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let decl = engine_state.get_decl(call.decl_id);
|
let decl = engine_state.get_decl(call.decl_id);
|
||||||
|
|
||||||
if !decl.is_known_external() && call.named.iter().any(|(flag, _)| flag.item == "help") {
|
if !decl.is_known_external() && call.named_iter().any(|(flag, _)| flag.item == "help") {
|
||||||
let mut signature = decl.signature();
|
let mut signature = decl.signature();
|
||||||
signature.usage = decl.usage().to_string();
|
signature.usage = decl.usage().to_string();
|
||||||
signature.extra_usage = decl.extra_usage().to_string();
|
signature.extra_usage = decl.extra_usage().to_string();
|
||||||
@ -59,7 +59,7 @@ pub fn eval_call(
|
|||||||
.var_id
|
.var_id
|
||||||
.expect("internal error: all custom parameters must have var_ids");
|
.expect("internal error: all custom parameters must have var_ids");
|
||||||
|
|
||||||
if let Some(arg) = call.positional.get(param_idx) {
|
if let Some(arg) = call.positional_nth(param_idx) {
|
||||||
let result = eval_expression(engine_state, caller_stack, arg)?;
|
let result = eval_expression(engine_state, caller_stack, arg)?;
|
||||||
callee_stack.add_var(var_id, result);
|
callee_stack.add_var(var_id, result);
|
||||||
} else if let Some(arg) = ¶m.default_value {
|
} else if let Some(arg) = ¶m.default_value {
|
||||||
@ -73,7 +73,7 @@ pub fn eval_call(
|
|||||||
if let Some(rest_positional) = decl.signature().rest_positional {
|
if let Some(rest_positional) = decl.signature().rest_positional {
|
||||||
let mut rest_items = vec![];
|
let mut rest_items = vec![];
|
||||||
|
|
||||||
for arg in call.positional.iter().skip(
|
for arg in call.positional_iter().skip(
|
||||||
decl.signature().required_positional.len()
|
decl.signature().required_positional.len()
|
||||||
+ decl.signature().optional_positional.len(),
|
+ decl.signature().optional_positional.len(),
|
||||||
) {
|
) {
|
||||||
@ -101,7 +101,7 @@ pub fn eval_call(
|
|||||||
for named in decl.signature().named {
|
for named in decl.signature().named {
|
||||||
if let Some(var_id) = named.var_id {
|
if let Some(var_id) = named.var_id {
|
||||||
let mut found = false;
|
let mut found = false;
|
||||||
for call_named in &call.named {
|
for call_named in call.named_iter() {
|
||||||
if call_named.0.item == named.long {
|
if call_named.0.item == named.long {
|
||||||
if let Some(arg) = &call_named.1 {
|
if let Some(arg) = &call_named.1 {
|
||||||
let result = eval_expression(engine_state, caller_stack, arg)?;
|
let result = eval_expression(engine_state, caller_stack, arg)?;
|
||||||
@ -198,14 +198,14 @@ fn eval_external(
|
|||||||
|
|
||||||
let mut call = Call::new(head.span);
|
let mut call = Call::new(head.span);
|
||||||
|
|
||||||
call.positional.push(head.clone());
|
call.add_positional(head.clone());
|
||||||
|
|
||||||
for arg in args {
|
for arg in args {
|
||||||
call.positional.push(arg.clone())
|
call.add_positional(arg.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
if redirect_stdout {
|
if redirect_stdout {
|
||||||
call.named.push((
|
call.add_named((
|
||||||
Spanned {
|
Spanned {
|
||||||
item: "redirect-stdout".into(),
|
item: "redirect-stdout".into(),
|
||||||
span: head.span,
|
span: head.span,
|
||||||
@ -215,7 +215,7 @@ fn eval_external(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if redirect_stderr {
|
if redirect_stderr {
|
||||||
call.named.push((
|
call.add_named((
|
||||||
Spanned {
|
Spanned {
|
||||||
item: "redirect-stderr".into(),
|
item: "redirect-stderr".into(),
|
||||||
span: head.span,
|
span: head.span,
|
||||||
|
@ -145,10 +145,10 @@ pub fn flatten_expression(
|
|||||||
let mut output = vec![(call.head, FlatShape::InternalCall)];
|
let mut output = vec![(call.head, FlatShape::InternalCall)];
|
||||||
|
|
||||||
let mut args = vec![];
|
let mut args = vec![];
|
||||||
for positional in &call.positional {
|
for positional in call.positional_iter() {
|
||||||
args.extend(flatten_expression(working_set, positional));
|
args.extend(flatten_expression(working_set, positional));
|
||||||
}
|
}
|
||||||
for named in &call.named {
|
for named in call.named_iter() {
|
||||||
args.push((named.0.span, FlatShape::Flag));
|
args.push((named.0.span, FlatShape::Flag));
|
||||||
if let Some(expr) = &named.1 {
|
if let Some(expr) = &named.1 {
|
||||||
args.extend(flatten_expression(working_set, expr));
|
args.extend(flatten_expression(working_set, expr));
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
use nu_protocol::ast::Expr;
|
|
||||||
use nu_protocol::engine::{EngineState, Stack, StateWorkingSet};
|
use nu_protocol::engine::{EngineState, Stack, StateWorkingSet};
|
||||||
use nu_protocol::{ast::Call, engine::Command, ShellError, Signature};
|
use nu_protocol::{
|
||||||
use nu_protocol::{PipelineData, Spanned};
|
ast::{Argument, Call, Expr, Expression},
|
||||||
|
engine::Command,
|
||||||
|
ShellError, Signature,
|
||||||
|
};
|
||||||
|
use nu_protocol::{PipelineData, Spanned, Type};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct KnownExternal {
|
pub struct KnownExternal {
|
||||||
@ -34,69 +37,56 @@ impl Command for KnownExternal {
|
|||||||
call: &Call,
|
call: &Call,
|
||||||
input: PipelineData,
|
input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
// FIXME: This is a bit of a hack, and it'd be nice for the parser/AST to be able to handle the original
|
|
||||||
// order of the parameters. Until then, we need to recover the original order.
|
|
||||||
|
|
||||||
// FIXME: This is going to be a bit expensive, but we need to do it to ensure any new block/subexpression
|
|
||||||
// we find when parsing the external call is handled properly.
|
|
||||||
let mut engine_state = engine_state.clone();
|
|
||||||
|
|
||||||
let call_span = call.span();
|
let call_span = call.span();
|
||||||
let contents = engine_state.get_span_contents(&call_span);
|
let head_span = call.head;
|
||||||
|
let decl_id = engine_state
|
||||||
|
.find_decl("run-external".as_bytes())
|
||||||
|
.ok_or(ShellError::ExternalNotSupported(head_span))?;
|
||||||
|
|
||||||
let redirect_stdout = call.redirect_stdout;
|
let command = engine_state.get_decl(decl_id);
|
||||||
let redirect_stderr = call.redirect_stderr;
|
|
||||||
|
|
||||||
let (lexed, _) = crate::lex(contents, call_span.start, &[], &[], true);
|
let mut extern_call = Call::new(head_span);
|
||||||
|
|
||||||
let spans: Vec<_> = lexed.into_iter().map(|x| x.span).collect();
|
let working_state = StateWorkingSet::new(engine_state);
|
||||||
let mut working_set = StateWorkingSet::new(&engine_state);
|
let extern_name = working_state.get_span_contents(call.head);
|
||||||
let (external_call, _) = crate::parse_external_call(&mut working_set, &spans, &[]);
|
let extern_name = String::from_utf8(extern_name.to_vec())
|
||||||
let delta = working_set.render();
|
.expect("this was already parsed as a command name");
|
||||||
engine_state.merge_delta(delta, None, ".")?;
|
let arg_extern_name = Expression {
|
||||||
|
expr: Expr::String(extern_name),
|
||||||
|
span: call.head,
|
||||||
|
ty: Type::String,
|
||||||
|
custom_completion: None,
|
||||||
|
};
|
||||||
|
|
||||||
match external_call.expr {
|
extern_call.add_positional(arg_extern_name);
|
||||||
Expr::ExternalCall(head, args) => {
|
|
||||||
let decl_id = engine_state
|
|
||||||
.find_decl("run-external".as_bytes())
|
|
||||||
.ok_or(ShellError::ExternalNotSupported(head.span))?;
|
|
||||||
|
|
||||||
let command = engine_state.get_decl(decl_id);
|
for arg in &call.arguments {
|
||||||
|
match arg {
|
||||||
let mut call = Call::new(head.span);
|
Argument::Positional(positional) => extern_call.add_positional(positional.clone()),
|
||||||
|
Argument::Named(named) => extern_call.add_named(named.clone()),
|
||||||
call.positional.push(*head);
|
|
||||||
|
|
||||||
for arg in args {
|
|
||||||
call.positional.push(arg.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
if redirect_stdout {
|
|
||||||
call.named.push((
|
|
||||||
Spanned {
|
|
||||||
item: "redirect-stdout".into(),
|
|
||||||
span: call_span,
|
|
||||||
},
|
|
||||||
None,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
if redirect_stderr {
|
|
||||||
call.named.push((
|
|
||||||
Spanned {
|
|
||||||
item: "redirect-stderr".into(),
|
|
||||||
span: call_span,
|
|
||||||
},
|
|
||||||
None,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
command.run(&engine_state, stack, &call, input)
|
|
||||||
}
|
|
||||||
x => {
|
|
||||||
println!("{:?}", x);
|
|
||||||
panic!("internal error: known external not actually external")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if call.redirect_stdout {
|
||||||
|
extern_call.add_named((
|
||||||
|
Spanned {
|
||||||
|
item: "redirect-stdout".into(),
|
||||||
|
span: call_span,
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
if call.redirect_stderr {
|
||||||
|
extern_call.add_named((
|
||||||
|
Spanned {
|
||||||
|
item: "redirect-stderr".into(),
|
||||||
|
span: call_span,
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
command.run(engine_state, stack, &extern_call, input)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use nu_path::canonicalize_with;
|
use nu_path::canonicalize_with;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::{
|
ast::{
|
||||||
Block, Call, Expr, Expression, ImportPattern, ImportPatternHead, ImportPatternMember,
|
Argument, Block, Call, Expr, Expression, ImportPattern, ImportPatternHead,
|
||||||
Pipeline,
|
ImportPatternMember, Pipeline,
|
||||||
},
|
},
|
||||||
engine::StateWorkingSet,
|
engine::StateWorkingSet,
|
||||||
span, Exportable, Overlay, PositionalArg, Span, SyntaxShape, Type, CONFIG_VARIABLE_ID,
|
span, Exportable, Overlay, PositionalArg, Span, SyntaxShape, Type, CONFIG_VARIABLE_ID,
|
||||||
@ -142,7 +142,7 @@ pub fn parse_for(
|
|||||||
let sig = decl.signature();
|
let sig = decl.signature();
|
||||||
|
|
||||||
// Let's get our block and make sure it has the right signature
|
// Let's get our block and make sure it has the right signature
|
||||||
if let Some(arg) = call.positional.get(2) {
|
if let Some(arg) = call.positional_nth(2) {
|
||||||
match arg {
|
match arg {
|
||||||
Expression {
|
Expression {
|
||||||
expr: Expr::Block(block_id),
|
expr: Expr::Block(block_id),
|
||||||
@ -178,8 +178,8 @@ pub fn parse_for(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// All positional arguments must be in the call positional vector by this point
|
// All positional arguments must be in the call positional vector by this point
|
||||||
let var_decl = call.positional.get(0).expect("for call already checked");
|
let var_decl = call.positional_nth(0).expect("for call already checked");
|
||||||
let block = call.positional.get(2).expect("for call already checked");
|
let block = call.positional_nth(2).expect("for call already checked");
|
||||||
|
|
||||||
let error = None;
|
let error = None;
|
||||||
if let (Some(var_id), Some(block_id)) = (&var_decl.as_var(), block.as_block()) {
|
if let (Some(var_id), Some(block_id)) = (&var_decl.as_var(), block.as_block()) {
|
||||||
@ -311,7 +311,7 @@ pub fn parse_def(
|
|||||||
let sig = decl.signature();
|
let sig = decl.signature();
|
||||||
|
|
||||||
// Let's get our block and make sure it has the right signature
|
// Let's get our block and make sure it has the right signature
|
||||||
if let Some(arg) = call.positional.get(2) {
|
if let Some(arg) = call.positional_nth(2) {
|
||||||
match arg {
|
match arg {
|
||||||
Expression {
|
Expression {
|
||||||
expr: Expr::Block(block_id),
|
expr: Expr::Block(block_id),
|
||||||
@ -347,9 +347,9 @@ pub fn parse_def(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// All positional arguments must be in the call positional vector by this point
|
// All positional arguments must be in the call positional vector by this point
|
||||||
let name_expr = call.positional.get(0).expect("def call already checked");
|
let name_expr = call.positional_nth(0).expect("def call already checked");
|
||||||
let sig = call.positional.get(1).expect("def call already checked");
|
let sig = call.positional_nth(1).expect("def call already checked");
|
||||||
let block = call.positional.get(2).expect("def call already checked");
|
let block = call.positional_nth(2).expect("def call already checked");
|
||||||
|
|
||||||
let mut error = None;
|
let mut error = None;
|
||||||
|
|
||||||
@ -457,8 +457,8 @@ pub fn parse_extern(
|
|||||||
(call, call_span)
|
(call, call_span)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let name_expr = call.positional.get(0);
|
let name_expr = call.positional_nth(0);
|
||||||
let sig = call.positional.get(1);
|
let sig = call.positional_nth(1);
|
||||||
|
|
||||||
if let (Some(name_expr), Some(sig)) = (name_expr, sig) {
|
if let (Some(name_expr), Some(sig)) = (name_expr, sig) {
|
||||||
if let (Some(name), Some(mut signature)) = (&name_expr.as_string(), sig.as_signature()) {
|
if let (Some(name), Some(mut signature)) = (&name_expr.as_string(), sig.as_signature()) {
|
||||||
@ -626,8 +626,7 @@ pub fn parse_export(
|
|||||||
let mut call = Box::new(Call {
|
let mut call = Box::new(Call {
|
||||||
head: spans[0],
|
head: spans[0],
|
||||||
decl_id: export_decl_id,
|
decl_id: export_decl_id,
|
||||||
positional: vec![],
|
arguments: vec![],
|
||||||
named: vec![],
|
|
||||||
redirect_stdout: true,
|
redirect_stdout: true,
|
||||||
redirect_stderr: false,
|
redirect_stderr: false,
|
||||||
});
|
});
|
||||||
@ -895,7 +894,7 @@ pub fn parse_export(
|
|||||||
if let Some(name_span) = spans.get(2) {
|
if let Some(name_span) = spans.get(2) {
|
||||||
let (name_expr, err) = parse_string(working_set, *name_span);
|
let (name_expr, err) = parse_string(working_set, *name_span);
|
||||||
error = error.or(err);
|
error = error.or(err);
|
||||||
call.positional.push(name_expr);
|
call.add_positional(name_expr);
|
||||||
|
|
||||||
if let Some(block_span) = spans.get(3) {
|
if let Some(block_span) = spans.get(3) {
|
||||||
let (block_expr, err) = parse_block_expression(
|
let (block_expr, err) = parse_block_expression(
|
||||||
@ -922,7 +921,7 @@ pub fn parse_export(
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
call.positional.push(block_expr);
|
call.add_positional(block_expr);
|
||||||
|
|
||||||
exportable
|
exportable
|
||||||
} else {
|
} else {
|
||||||
@ -1184,8 +1183,10 @@ pub fn parse_module(
|
|||||||
let call = Box::new(Call {
|
let call = Box::new(Call {
|
||||||
head: spans[0],
|
head: spans[0],
|
||||||
decl_id: module_decl_id,
|
decl_id: module_decl_id,
|
||||||
positional: vec![module_name_expr, block_expr],
|
arguments: vec![
|
||||||
named: vec![],
|
Argument::Positional(module_name_expr),
|
||||||
|
Argument::Positional(block_expr),
|
||||||
|
],
|
||||||
redirect_stdout: true,
|
redirect_stdout: true,
|
||||||
redirect_stderr: false,
|
redirect_stderr: false,
|
||||||
});
|
});
|
||||||
@ -1264,7 +1265,7 @@ pub fn parse_use(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let import_pattern = if let Some(expr) = call.nth(0) {
|
let import_pattern = if let Some(expr) = call.positional_nth(0) {
|
||||||
if let Some(pattern) = expr.as_import_pattern() {
|
if let Some(pattern) = expr.as_import_pattern() {
|
||||||
pattern
|
pattern
|
||||||
} else {
|
} else {
|
||||||
@ -1422,8 +1423,7 @@ pub fn parse_use(
|
|||||||
let call = Box::new(Call {
|
let call = Box::new(Call {
|
||||||
head: spans[0],
|
head: spans[0],
|
||||||
decl_id: use_decl_id,
|
decl_id: use_decl_id,
|
||||||
positional: vec![import_pattern_expr],
|
arguments: vec![Argument::Positional(import_pattern_expr)],
|
||||||
named: vec![],
|
|
||||||
redirect_stdout: true,
|
redirect_stdout: true,
|
||||||
redirect_stderr: false,
|
redirect_stderr: false,
|
||||||
});
|
});
|
||||||
@ -1493,7 +1493,7 @@ pub fn parse_hide(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let import_pattern = if let Some(expr) = call.nth(0) {
|
let import_pattern = if let Some(expr) = call.positional_nth(0) {
|
||||||
if let Some(pattern) = expr.as_import_pattern() {
|
if let Some(pattern) = expr.as_import_pattern() {
|
||||||
pattern
|
pattern
|
||||||
} else {
|
} else {
|
||||||
@ -1630,8 +1630,7 @@ pub fn parse_hide(
|
|||||||
let call = Box::new(Call {
|
let call = Box::new(Call {
|
||||||
head: spans[0],
|
head: spans[0],
|
||||||
decl_id: hide_decl_id,
|
decl_id: hide_decl_id,
|
||||||
positional: vec![import_pattern_expr],
|
arguments: vec![Argument::Positional(import_pattern_expr)],
|
||||||
named: vec![],
|
|
||||||
redirect_stdout: true,
|
redirect_stdout: true,
|
||||||
redirect_stderr: false,
|
redirect_stderr: false,
|
||||||
});
|
});
|
||||||
@ -1715,8 +1714,10 @@ pub fn parse_let(
|
|||||||
let call = Box::new(Call {
|
let call = Box::new(Call {
|
||||||
decl_id,
|
decl_id,
|
||||||
head: spans[0],
|
head: spans[0],
|
||||||
positional: vec![lvalue, rvalue],
|
arguments: vec![
|
||||||
named: vec![],
|
Argument::Positional(lvalue),
|
||||||
|
Argument::Positional(rvalue),
|
||||||
|
],
|
||||||
redirect_stdout: true,
|
redirect_stdout: true,
|
||||||
redirect_stderr: false,
|
redirect_stderr: false,
|
||||||
});
|
});
|
||||||
@ -1834,7 +1835,7 @@ pub fn parse_source(
|
|||||||
|
|
||||||
// Adding this expression to the positional creates a syntax highlighting error
|
// Adding this expression to the positional creates a syntax highlighting error
|
||||||
// after writing `source example.nu`
|
// after writing `source example.nu`
|
||||||
call_with_block.positional.push(Expression {
|
call_with_block.add_positional(Expression {
|
||||||
expr: Expr::Int(block_id as i64),
|
expr: Expr::Int(block_id as i64),
|
||||||
span: spans[1],
|
span: spans[1],
|
||||||
ty: Type::Any,
|
ty: Type::Any,
|
||||||
@ -1947,8 +1948,7 @@ pub fn parse_register(
|
|||||||
// The ? operator is not used because the error has to be kept to be printed in the shell
|
// The ? operator is not used because the error has to be kept to be printed in the shell
|
||||||
// For that reason the values are kept in a result that will be passed at the end of this call
|
// For that reason the values are kept in a result that will be passed at the end of this call
|
||||||
let arguments = call
|
let arguments = call
|
||||||
.positional
|
.positional_nth(0)
|
||||||
.get(0)
|
|
||||||
.map(|expr| {
|
.map(|expr| {
|
||||||
let name_expr = working_set.get_span_contents(expr.span);
|
let name_expr = working_set.get_span_contents(expr.span);
|
||||||
|
|
||||||
@ -1992,7 +1992,7 @@ pub fn parse_register(
|
|||||||
|
|
||||||
// Signature is an optional value from the call and will be used to decide if
|
// Signature is an optional value from the call and will be used to decide if
|
||||||
// the plugin is called to get the signatures or to use the given signature
|
// the plugin is called to get the signatures or to use the given signature
|
||||||
let signature = call.positional.get(1).map(|expr| {
|
let signature = call.positional_nth(1).map(|expr| {
|
||||||
let signature = working_set.get_span_contents(expr.span);
|
let signature = working_set.get_span_contents(expr.span);
|
||||||
serde_json::from_slice::<Signature>(signature).map_err(|_| {
|
serde_json::from_slice::<Signature>(signature).map_err(|_| {
|
||||||
ParseError::LabeledError(
|
ParseError::LabeledError(
|
||||||
|
@ -8,8 +8,9 @@ use crate::{
|
|||||||
|
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::{
|
ast::{
|
||||||
Block, Call, CellPath, Expr, Expression, FullCellPath, ImportPattern, ImportPatternHead,
|
Argument, Block, Call, CellPath, Expr, Expression, FullCellPath, ImportPattern,
|
||||||
ImportPatternMember, Operator, PathMember, Pipeline, RangeInclusion, RangeOperator,
|
ImportPatternHead, ImportPatternMember, Operator, PathMember, Pipeline, RangeInclusion,
|
||||||
|
RangeOperator,
|
||||||
},
|
},
|
||||||
engine::StateWorkingSet,
|
engine::StateWorkingSet,
|
||||||
span, BlockId, Flag, PositionalArg, Signature, Span, Spanned, SyntaxShape, Type, Unit, VarId,
|
span, BlockId, Flag, PositionalArg, Signature, Span, Spanned, SyntaxShape, Type, Unit, VarId,
|
||||||
@ -127,16 +128,16 @@ pub fn trim_quotes(bytes: &[u8]) -> &[u8] {
|
|||||||
|
|
||||||
pub fn check_call(command: Span, sig: &Signature, call: &Call) -> Option<ParseError> {
|
pub fn check_call(command: Span, sig: &Signature, call: &Call) -> Option<ParseError> {
|
||||||
// Allow the call to pass if they pass in the help flag
|
// Allow the call to pass if they pass in the help flag
|
||||||
if call.named.iter().any(|(n, _)| n.item == "help") {
|
if call.named_iter().any(|(n, _)| n.item == "help") {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
if call.positional.len() < sig.required_positional.len() {
|
if call.positional_len() < sig.required_positional.len() {
|
||||||
// Comparing the types of all signature positional arguments against the parsed
|
// Comparing the types of all signature positional arguments against the parsed
|
||||||
// expressions found in the call. If one type is not found then it could be assumed
|
// expressions found in the call. If one type is not found then it could be assumed
|
||||||
// that that positional argument is missing from the parsed call
|
// that that positional argument is missing from the parsed call
|
||||||
for argument in &sig.required_positional {
|
for argument in &sig.required_positional {
|
||||||
let found = call.positional.iter().fold(false, |ac, expr| {
|
let found = call.positional_iter().fold(false, |ac, expr| {
|
||||||
if argument.shape.to_type() == expr.ty || argument.shape == SyntaxShape::Any {
|
if argument.shape.to_type() == expr.ty || argument.shape == SyntaxShape::Any {
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
@ -144,7 +145,7 @@ pub fn check_call(command: Span, sig: &Signature, call: &Call) -> Option<ParseEr
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
if !found {
|
if !found {
|
||||||
if let Some(last) = call.positional.last() {
|
if let Some(last) = call.positional_iter().last() {
|
||||||
return Some(ParseError::MissingPositional(
|
return Some(ParseError::MissingPositional(
|
||||||
argument.name.clone(),
|
argument.name.clone(),
|
||||||
Span {
|
Span {
|
||||||
@ -166,8 +167,8 @@ pub fn check_call(command: Span, sig: &Signature, call: &Call) -> Option<ParseEr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let missing = &sig.required_positional[call.positional.len()];
|
let missing = &sig.required_positional[call.positional_len()];
|
||||||
if let Some(last) = call.positional.last() {
|
if let Some(last) = call.positional_iter().last() {
|
||||||
Some(ParseError::MissingPositional(
|
Some(ParseError::MissingPositional(
|
||||||
missing.name.clone(),
|
missing.name.clone(),
|
||||||
Span {
|
Span {
|
||||||
@ -188,7 +189,7 @@ pub fn check_call(command: Span, sig: &Signature, call: &Call) -> Option<ParseEr
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for req_flag in sig.named.iter().filter(|x| x.required) {
|
for req_flag in sig.named.iter().filter(|x| x.required) {
|
||||||
if call.named.iter().all(|(n, _)| n.item != req_flag.long) {
|
if call.named_iter().all(|(n, _)| n.item != req_flag.long) {
|
||||||
return Some(ParseError::MissingRequiredFlag(
|
return Some(ParseError::MissingRequiredFlag(
|
||||||
req_flag.long.clone(),
|
req_flag.long.clone(),
|
||||||
command,
|
command,
|
||||||
@ -743,7 +744,7 @@ pub fn parse_internal_call(
|
|||||||
if let Some(long_name) = long_name {
|
if let Some(long_name) = long_name {
|
||||||
// We found a long flag, like --bar
|
// We found a long flag, like --bar
|
||||||
error = error.or(err);
|
error = error.or(err);
|
||||||
call.named.push((long_name, arg));
|
call.add_named((long_name, arg));
|
||||||
spans_idx += 1;
|
spans_idx += 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -766,7 +767,7 @@ pub fn parse_internal_call(
|
|||||||
parse_value(working_set, *arg, &arg_shape, expand_aliases_denylist);
|
parse_value(working_set, *arg, &arg_shape, expand_aliases_denylist);
|
||||||
error = error.or(err);
|
error = error.or(err);
|
||||||
|
|
||||||
call.named.push((
|
call.add_named((
|
||||||
Spanned {
|
Spanned {
|
||||||
item: flag.long.clone(),
|
item: flag.long.clone(),
|
||||||
span: spans[spans_idx],
|
span: spans[spans_idx],
|
||||||
@ -783,7 +784,7 @@ pub fn parse_internal_call(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
call.named.push((
|
call.add_named((
|
||||||
Spanned {
|
Spanned {
|
||||||
item: flag.long.clone(),
|
item: flag.long.clone(),
|
||||||
span: spans[spans_idx],
|
span: spans[spans_idx],
|
||||||
@ -844,10 +845,10 @@ pub fn parse_internal_call(
|
|||||||
} else {
|
} else {
|
||||||
arg
|
arg
|
||||||
};
|
};
|
||||||
call.positional.push(arg);
|
call.add_positional(arg);
|
||||||
positional_idx += 1;
|
positional_idx += 1;
|
||||||
} else {
|
} else {
|
||||||
call.positional.push(Expression::garbage(arg_span));
|
call.add_positional(Expression::garbage(arg_span));
|
||||||
error = error.or_else(|| {
|
error = error.or_else(|| {
|
||||||
Some(ParseError::ExtraPositional(
|
Some(ParseError::ExtraPositional(
|
||||||
signature.call_signature(),
|
signature.call_signature(),
|
||||||
@ -4384,26 +4385,25 @@ pub fn parse_expression(
|
|||||||
env_vars.push(sh.1);
|
env_vars.push(sh.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
let positional = vec![
|
let arguments = vec![
|
||||||
Expression {
|
Argument::Positional(Expression {
|
||||||
expr: Expr::List(env_vars),
|
expr: Expr::List(env_vars),
|
||||||
span: span(&spans[..pos]),
|
span: span(&spans[..pos]),
|
||||||
ty: Type::Any,
|
ty: Type::Any,
|
||||||
custom_completion: None,
|
custom_completion: None,
|
||||||
},
|
}),
|
||||||
Expression {
|
Argument::Positional(Expression {
|
||||||
expr: Expr::Block(block_id),
|
expr: Expr::Block(block_id),
|
||||||
span: span(&spans[pos..]),
|
span: span(&spans[pos..]),
|
||||||
ty,
|
ty,
|
||||||
custom_completion: None,
|
custom_completion: None,
|
||||||
},
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
let expr = Expr::Call(Box::new(Call {
|
let expr = Expr::Call(Box::new(Call {
|
||||||
head: Span { start: 0, end: 0 },
|
head: Span { start: 0, end: 0 },
|
||||||
decl_id,
|
decl_id,
|
||||||
named: vec![],
|
arguments,
|
||||||
positional,
|
|
||||||
redirect_stdout: true,
|
redirect_stdout: true,
|
||||||
redirect_stderr: false,
|
redirect_stderr: false,
|
||||||
}));
|
}));
|
||||||
@ -4657,7 +4657,7 @@ pub fn parse_block(
|
|||||||
if let Some(Expression {
|
if let Some(Expression {
|
||||||
expr: Expr::Keyword(_, _, expr),
|
expr: Expr::Keyword(_, _, expr),
|
||||||
..
|
..
|
||||||
}) = call.positional.get_mut(1)
|
}) = call.positional_iter_mut().nth(1)
|
||||||
{
|
{
|
||||||
if expr.has_in_variable(working_set) {
|
if expr.has_in_variable(working_set) {
|
||||||
*expr = Box::new(wrap_expr_with_collect(
|
*expr = Box::new(wrap_expr_with_collect(
|
||||||
@ -4810,14 +4810,14 @@ pub fn discover_captures_in_expr(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for named in &call.named {
|
for named in call.named_iter() {
|
||||||
if let Some(arg) = &named.1 {
|
if let Some(arg) = &named.1 {
|
||||||
let result = discover_captures_in_expr(working_set, arg, seen, seen_blocks);
|
let result = discover_captures_in_expr(working_set, arg, seen, seen_blocks);
|
||||||
output.extend(&result);
|
output.extend(&result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for positional in &call.positional {
|
for positional in call.positional_iter() {
|
||||||
let result = discover_captures_in_expr(working_set, positional, seen, seen_blocks);
|
let result = discover_captures_in_expr(working_set, positional, seen, seen_blocks);
|
||||||
output.extend(&result);
|
output.extend(&result);
|
||||||
}
|
}
|
||||||
@ -4985,12 +4985,12 @@ fn wrap_expr_with_collect(working_set: &mut StateWorkingSet, expr: &Expression)
|
|||||||
|
|
||||||
let block_id = working_set.add_block(block);
|
let block_id = working_set.add_block(block);
|
||||||
|
|
||||||
output.push(Expression {
|
output.push(Argument::Positional(Expression {
|
||||||
expr: Expr::Block(block_id),
|
expr: Expr::Block(block_id),
|
||||||
span,
|
span,
|
||||||
ty: Type::Any,
|
ty: Type::Any,
|
||||||
custom_completion: None,
|
custom_completion: None,
|
||||||
});
|
}));
|
||||||
|
|
||||||
// The containing, synthetic call to `collect`.
|
// The containing, synthetic call to `collect`.
|
||||||
// We don't want to have a real span as it will confuse flattening
|
// We don't want to have a real span as it will confuse flattening
|
||||||
@ -4998,8 +4998,7 @@ fn wrap_expr_with_collect(working_set: &mut StateWorkingSet, expr: &Expression)
|
|||||||
Expression {
|
Expression {
|
||||||
expr: Expr::Call(Box::new(Call {
|
expr: Expr::Call(Box::new(Call {
|
||||||
head: Span::new(0, 0),
|
head: Span::new(0, 0),
|
||||||
named: vec![],
|
arguments: output,
|
||||||
positional: output,
|
|
||||||
decl_id,
|
decl_id,
|
||||||
redirect_stdout: true,
|
redirect_stdout: true,
|
||||||
redirect_stderr: false,
|
redirect_stderr: false,
|
||||||
|
@ -24,13 +24,12 @@ impl EvaluatedCall {
|
|||||||
stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
) -> Result<Self, ShellError> {
|
) -> Result<Self, ShellError> {
|
||||||
let positional = call
|
let positional = call
|
||||||
.positional
|
.positional_iter()
|
||||||
.iter()
|
|
||||||
.map(|expr| eval_expression(engine_state, stack, expr))
|
.map(|expr| eval_expression(engine_state, stack, expr))
|
||||||
.collect::<Result<Vec<Value>, ShellError>>()?;
|
.collect::<Result<Vec<Value>, ShellError>>()?;
|
||||||
|
|
||||||
let mut named = Vec::with_capacity(call.named.len());
|
let mut named = Vec::with_capacity(call.named_len());
|
||||||
for (string, expr) in call.named.iter() {
|
for (string, expr) in call.named_iter() {
|
||||||
let value = match expr {
|
let value = match expr {
|
||||||
None => None,
|
None => None,
|
||||||
Some(expr) => Some(eval_expression(engine_state, stack, expr)?),
|
Some(expr) => Some(eval_expression(engine_state, stack, expr)?),
|
||||||
|
@ -3,13 +3,18 @@ use serde::{Deserialize, Serialize};
|
|||||||
use super::Expression;
|
use super::Expression;
|
||||||
use crate::{DeclId, Span, Spanned};
|
use crate::{DeclId, Span, Spanned};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub enum Argument {
|
||||||
|
Positional(Expression),
|
||||||
|
Named((Spanned<String>, Option<Expression>)),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct Call {
|
pub struct Call {
|
||||||
/// identifier of the declaration to call
|
/// identifier of the declaration to call
|
||||||
pub decl_id: DeclId,
|
pub decl_id: DeclId,
|
||||||
pub head: Span,
|
pub head: Span,
|
||||||
pub positional: Vec<Expression>,
|
pub arguments: Vec<Argument>,
|
||||||
pub named: Vec<(Spanned<String>, Option<Expression>)>,
|
|
||||||
pub redirect_stdout: bool,
|
pub redirect_stdout: bool,
|
||||||
pub redirect_stderr: bool,
|
pub redirect_stderr: bool,
|
||||||
}
|
}
|
||||||
@ -19,15 +24,64 @@ impl Call {
|
|||||||
Self {
|
Self {
|
||||||
decl_id: 0,
|
decl_id: 0,
|
||||||
head,
|
head,
|
||||||
positional: vec![],
|
arguments: vec![],
|
||||||
named: vec![],
|
|
||||||
redirect_stdout: true,
|
redirect_stdout: true,
|
||||||
redirect_stderr: false,
|
redirect_stderr: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn named_iter(&self) -> impl Iterator<Item = &(Spanned<String>, Option<Expression>)> {
|
||||||
|
self.arguments.iter().filter_map(|arg| match arg {
|
||||||
|
Argument::Named(named) => Some(named),
|
||||||
|
Argument::Positional(_) => None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn named_iter_mut(
|
||||||
|
&mut self,
|
||||||
|
) -> impl Iterator<Item = &mut (Spanned<String>, Option<Expression>)> {
|
||||||
|
self.arguments.iter_mut().filter_map(|arg| match arg {
|
||||||
|
Argument::Named(named) => Some(named),
|
||||||
|
Argument::Positional(_) => None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn named_len(&self) -> usize {
|
||||||
|
self.named_iter().count()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_named(&mut self, named: (Spanned<String>, Option<Expression>)) {
|
||||||
|
self.arguments.push(Argument::Named(named));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_positional(&mut self, positional: Expression) {
|
||||||
|
self.arguments.push(Argument::Positional(positional));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn positional_iter(&self) -> impl Iterator<Item = &Expression> {
|
||||||
|
self.arguments.iter().filter_map(|arg| match arg {
|
||||||
|
Argument::Named(_) => None,
|
||||||
|
Argument::Positional(positional) => Some(positional),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn positional_iter_mut(&mut self) -> impl Iterator<Item = &mut Expression> {
|
||||||
|
self.arguments.iter_mut().filter_map(|arg| match arg {
|
||||||
|
Argument::Named(_) => None,
|
||||||
|
Argument::Positional(positional) => Some(positional),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn positional_nth(&self, i: usize) -> Option<&Expression> {
|
||||||
|
self.positional_iter().nth(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn positional_len(&self) -> usize {
|
||||||
|
self.positional_iter().count()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn has_flag(&self, flag_name: &str) -> bool {
|
pub fn has_flag(&self, flag_name: &str) -> bool {
|
||||||
for name in &self.named {
|
for name in self.named_iter() {
|
||||||
if flag_name == name.0.item {
|
if flag_name == name.0.item {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -37,7 +91,7 @@ impl Call {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_flag_expr(&self, flag_name: &str) -> Option<Expression> {
|
pub fn get_flag_expr(&self, flag_name: &str) -> Option<Expression> {
|
||||||
for name in &self.named {
|
for name in self.named_iter() {
|
||||||
if flag_name == name.0.item {
|
if flag_name == name.0.item {
|
||||||
return name.1.clone();
|
return name.1.clone();
|
||||||
}
|
}
|
||||||
@ -47,7 +101,7 @@ impl Call {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_named_arg(&self, flag_name: &str) -> Option<Spanned<String>> {
|
pub fn get_named_arg(&self, flag_name: &str) -> Option<Spanned<String>> {
|
||||||
for name in &self.named {
|
for name in self.named_iter() {
|
||||||
if flag_name == name.0.item {
|
if flag_name == name.0.item {
|
||||||
return Some(name.0.clone());
|
return Some(name.0.clone());
|
||||||
}
|
}
|
||||||
@ -56,20 +110,16 @@ impl Call {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn nth(&self, pos: usize) -> Option<Expression> {
|
|
||||||
self.positional.get(pos).cloned()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn span(&self) -> Span {
|
pub fn span(&self) -> Span {
|
||||||
let mut span = self.head;
|
let mut span = self.head;
|
||||||
|
|
||||||
for positional in &self.positional {
|
for positional in self.positional_iter() {
|
||||||
if positional.span.end > span.end {
|
if positional.span.end > span.end {
|
||||||
span.end = positional.span.end;
|
span.end = positional.span.end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (named, val) in &self.named {
|
for (named, val) in self.named_iter() {
|
||||||
if named.span.end > span.end {
|
if named.span.end > span.end {
|
||||||
span.end = named.span.end;
|
span.end = named.span.end;
|
||||||
}
|
}
|
||||||
|
@ -133,12 +133,12 @@ impl Expression {
|
|||||||
Expr::Binary(_) => false,
|
Expr::Binary(_) => false,
|
||||||
Expr::Bool(_) => false,
|
Expr::Bool(_) => false,
|
||||||
Expr::Call(call) => {
|
Expr::Call(call) => {
|
||||||
for positional in &call.positional {
|
for positional in call.positional_iter() {
|
||||||
if positional.has_in_variable(working_set) {
|
if positional.has_in_variable(working_set) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for named in &call.named {
|
for named in call.named_iter() {
|
||||||
if let Some(expr) = &named.1 {
|
if let Some(expr) = &named.1 {
|
||||||
if expr.has_in_variable(working_set) {
|
if expr.has_in_variable(working_set) {
|
||||||
return true;
|
return true;
|
||||||
@ -302,10 +302,10 @@ impl Expression {
|
|||||||
Expr::Binary(_) => {}
|
Expr::Binary(_) => {}
|
||||||
Expr::Bool(_) => {}
|
Expr::Bool(_) => {}
|
||||||
Expr::Call(call) => {
|
Expr::Call(call) => {
|
||||||
for positional in &mut call.positional {
|
for positional in call.positional_iter_mut() {
|
||||||
positional.replace_in_variable(working_set, new_var_id);
|
positional.replace_in_variable(working_set, new_var_id);
|
||||||
}
|
}
|
||||||
for named in &mut call.named {
|
for named in call.named_iter_mut() {
|
||||||
if let Some(expr) = &mut named.1 {
|
if let Some(expr) = &mut named.1 {
|
||||||
expr.replace_in_variable(working_set, new_var_id)
|
expr.replace_in_variable(working_set, new_var_id)
|
||||||
}
|
}
|
||||||
@ -449,10 +449,10 @@ impl Expression {
|
|||||||
if replaced.contains_span(call.head) {
|
if replaced.contains_span(call.head) {
|
||||||
call.head = new_span;
|
call.head = new_span;
|
||||||
}
|
}
|
||||||
for positional in &mut call.positional {
|
for positional in call.positional_iter_mut() {
|
||||||
positional.replace_span(working_set, replaced, new_span);
|
positional.replace_span(working_set, replaced, new_span);
|
||||||
}
|
}
|
||||||
for named in &mut call.named {
|
for named in call.named_iter_mut() {
|
||||||
if let Some(expr) = &mut named.1 {
|
if let Some(expr) = &mut named.1 {
|
||||||
expr.replace_span(working_set, replaced, new_span)
|
expr.replace_span(working_set, replaced, new_span)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user