forked from extern/nushell
Add explicit block params (#3444)
* Add explicit block params * Add explicit block params
This commit is contained in:
parent
0ff08bb63a
commit
e2973d2176
@ -37,7 +37,7 @@ impl<'s> Flatten<'s> {
|
||||
)
|
||||
.collect(),
|
||||
Expression::Command => vec![LocationType::Command.spanned(e.span)],
|
||||
Expression::Path(path) => self.expression(&path.head),
|
||||
Expression::FullColumnPath(path) => self.expression(&path.head),
|
||||
Expression::Variable(_, _) => vec![LocationType::Variable.spanned(e.span)],
|
||||
|
||||
Expression::Boolean(_)
|
||||
|
@ -296,7 +296,7 @@ fn get_shape_of_expr(expr: &SpannedExpression) -> Option<SyntaxShape> {
|
||||
Expression::List(_) => Some(SyntaxShape::Table),
|
||||
Expression::Boolean(_) => Some(SyntaxShape::String),
|
||||
|
||||
Expression::Path(_) => Some(SyntaxShape::ColumnPath),
|
||||
Expression::FullColumnPath(_) => Some(SyntaxShape::ColumnPath),
|
||||
Expression::FilePath(_) => Some(SyntaxShape::FilePath),
|
||||
Expression::Block(_) => Some(SyntaxShape::Block),
|
||||
Expression::ExternalCommand(_) => Some(SyntaxShape::String),
|
||||
@ -539,7 +539,7 @@ impl VarSyntaxShapeDeductor {
|
||||
trace!("Inferring vars in block");
|
||||
self.infer_shape(&b, scope)?;
|
||||
}
|
||||
Expression::Path(path) => {
|
||||
Expression::FullColumnPath(path) => {
|
||||
trace!("Inferring vars in path");
|
||||
match &path.head.expr {
|
||||
//PathMember can't be var yet (?)
|
||||
@ -790,7 +790,7 @@ impl VarSyntaxShapeDeductor {
|
||||
| Expression::Binary(_)
|
||||
| Expression::Range(_)
|
||||
| Expression::Block(_)
|
||||
| Expression::Path(_)
|
||||
| Expression::FullColumnPath(_)
|
||||
| Expression::FilePath(_)
|
||||
| Expression::ExternalCommand(_)
|
||||
| Expression::Command
|
||||
|
@ -55,6 +55,15 @@ impl WholeStreamCommand for Each {
|
||||
"echo ['bob' 'fred'] | each --numbered { echo $\"{$it.index} is {$it.item}\" }",
|
||||
result: Some(vec![Value::from("0 is bob"), Value::from("1 is fred")]),
|
||||
},
|
||||
Example {
|
||||
description: "Name the block variable that each uses",
|
||||
example: "[1, 2, 3] | each {|x| $x + 100}",
|
||||
result: Some(vec![
|
||||
UntaggedValue::int(101).into(),
|
||||
UntaggedValue::int(102).into(),
|
||||
UntaggedValue::int(103).into(),
|
||||
]),
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -159,7 +159,7 @@ pub fn evaluate_baseline_expr(
|
||||
.into_value(&tag),
|
||||
)
|
||||
}
|
||||
Expression::Path(path) => {
|
||||
Expression::FullColumnPath(path) => {
|
||||
let value = evaluate_baseline_expr(&path.head, ctx)?;
|
||||
let mut item = value;
|
||||
|
||||
|
@ -13,12 +13,18 @@ use nu_protocol::{NamedType, PositionalType, Signature, SyntaxShape, UnspannedPa
|
||||
use nu_source::{HasSpan, Span, Spanned, SpannedItem};
|
||||
use num_bigint::BigInt;
|
||||
|
||||
use crate::lex::tokens::{LiteBlock, LiteCommand, LitePipeline};
|
||||
use crate::path::expand_path;
|
||||
use crate::{
|
||||
lex::lexer::{lex, parse_block},
|
||||
ParserScope,
|
||||
};
|
||||
use crate::{
|
||||
lex::{
|
||||
lexer::Token,
|
||||
tokens::{LiteBlock, LiteCommand, LitePipeline, TokenContents},
|
||||
},
|
||||
parse::def::lex_split_baseline_tokens_on,
|
||||
};
|
||||
use crate::{parse::def::parse_parameter, path::expand_path};
|
||||
|
||||
use self::{
|
||||
def::{parse_definition, parse_definition_prototype},
|
||||
@ -919,20 +925,78 @@ fn parse_arg(
|
||||
let string: String = chars.collect();
|
||||
|
||||
// We haven't done much with the inner string, so let's go ahead and work with it
|
||||
let (tokens, err) = lex(&string, lite_arg.span.start() + 1);
|
||||
let (mut tokens, err) = lex(&string, lite_arg.span.start() + 1);
|
||||
if err.is_some() {
|
||||
return (garbage(lite_arg.span), err);
|
||||
}
|
||||
|
||||
// Check to see if we have parameters
|
||||
let params = if matches!(
|
||||
tokens.first(),
|
||||
Some(Token {
|
||||
contents: TokenContents::Pipe,
|
||||
..
|
||||
})
|
||||
) {
|
||||
// We've found a parameter list
|
||||
let mut param_tokens = vec![];
|
||||
let mut token_iter = tokens.into_iter().skip(1);
|
||||
while let Some(token) = token_iter.next() {
|
||||
if matches!(
|
||||
token,
|
||||
Token {
|
||||
contents: TokenContents::Pipe,
|
||||
..
|
||||
}
|
||||
) {
|
||||
break;
|
||||
} else {
|
||||
param_tokens.push(token);
|
||||
}
|
||||
}
|
||||
let split_tokens =
|
||||
lex_split_baseline_tokens_on(param_tokens, &[',', ':', '?']);
|
||||
|
||||
let mut i = 0;
|
||||
let mut params = vec![];
|
||||
|
||||
while i < split_tokens.len() {
|
||||
let (parameter, advance_by, error) =
|
||||
parse_parameter(&split_tokens[i..], split_tokens[i].span);
|
||||
|
||||
if error.is_some() {
|
||||
return (garbage(lite_arg.span), error);
|
||||
}
|
||||
i += advance_by;
|
||||
params.push(parameter);
|
||||
}
|
||||
|
||||
tokens = token_iter.collect();
|
||||
params
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
|
||||
let (lite_block, err) = parse_block(tokens);
|
||||
if err.is_some() {
|
||||
return (garbage(lite_arg.span), err);
|
||||
}
|
||||
|
||||
scope.enter_scope();
|
||||
let (classified_block, err) = classify_block(&lite_block, scope);
|
||||
let (mut classified_block, err) = classify_block(&lite_block, scope);
|
||||
scope.exit_scope();
|
||||
|
||||
if !params.is_empty() && classified_block.params.positional.is_empty() {
|
||||
if let Some(classified_block) = Arc::get_mut(&mut classified_block) {
|
||||
for param in params {
|
||||
classified_block
|
||||
.params
|
||||
.positional
|
||||
.push((param.pos_type, param.desc.unwrap_or_default()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(
|
||||
SpannedExpression::new(Expression::Block(classified_block), lite_arg.span),
|
||||
err,
|
||||
@ -1600,16 +1664,11 @@ fn parse_call(
|
||||
})),
|
||||
error,
|
||||
);
|
||||
// } else if lite_cmd.parts[0].item.starts_with('(') {
|
||||
// let (expr, err) = parse_simple_invocation(&lite_cmd.parts[0], scope);
|
||||
// error = error.or(err);
|
||||
// return (Some(ClassifiedCommand::Expr(Box::new(expr))), error);
|
||||
} else if lite_cmd.parts[0].item.starts_with('{') {
|
||||
return parse_value_call(lite_cmd, scope);
|
||||
} else if lite_cmd.parts[0].item.starts_with('$')
|
||||
|| lite_cmd.parts[0].item.starts_with('\"')
|
||||
|| lite_cmd.parts[0].item.starts_with('\'')
|
||||
|| lite_cmd.parts[0].item.starts_with('`')
|
||||
|| lite_cmd.parts[0].item.starts_with('-')
|
||||
|| lite_cmd.parts[0].item.starts_with('0')
|
||||
|| lite_cmd.parts[0].item.starts_with('1')
|
||||
|
@ -16,6 +16,7 @@ use crate::lex::lexer::{lex, parse_block};
|
||||
use crate::ParserScope;
|
||||
|
||||
use self::signature::parse_signature;
|
||||
pub use self::signature::{lex_split_baseline_tokens_on, parse_parameter};
|
||||
|
||||
mod data_structs;
|
||||
mod primitives;
|
||||
|
@ -87,7 +87,7 @@ pub fn parse_signature(
|
||||
i += advanced_by;
|
||||
rest = rest_;
|
||||
} else {
|
||||
let (parameter, advanced_by, error) = parse_parameter(&tokens[i..], signature_vec);
|
||||
let (parameter, advanced_by, error) = parse_parameter(&tokens[i..], signature_vec.span);
|
||||
err = err.or(error);
|
||||
i += advanced_by;
|
||||
parameters.push(parameter);
|
||||
@ -100,16 +100,13 @@ pub fn parse_signature(
|
||||
(signature, err)
|
||||
}
|
||||
|
||||
fn parse_parameter(
|
||||
tokens: &[Token],
|
||||
tokens_as_str: &Spanned<String>,
|
||||
) -> (Parameter, usize, Option<ParseError>) {
|
||||
pub fn parse_parameter(tokens: &[Token], span: Span) -> (Parameter, usize, Option<ParseError>) {
|
||||
if tokens.is_empty() {
|
||||
//TODO fix span
|
||||
return (
|
||||
Parameter::error(),
|
||||
0,
|
||||
Some(ParseError::unexpected_eof("parameter", tokens_as_str.span)),
|
||||
Some(ParseError::unexpected_eof("parameter", span)),
|
||||
);
|
||||
}
|
||||
|
||||
@ -145,9 +142,15 @@ fn parse_parameter(
|
||||
}
|
||||
|
||||
let pos_type = if optional {
|
||||
PositionalType::optional(&name.item, type_)
|
||||
} else {
|
||||
if name.item.starts_with('$') {
|
||||
PositionalType::optional(&name.item, type_)
|
||||
} else {
|
||||
PositionalType::optional(&format!("${}", name.item), type_)
|
||||
}
|
||||
} else if name.item.starts_with('$') {
|
||||
PositionalType::mandatory(&name.item, type_)
|
||||
} else {
|
||||
PositionalType::mandatory(&format!("${}", name.item), type_)
|
||||
};
|
||||
|
||||
let parameter = Parameter::new(pos_type, comment, name.span);
|
||||
@ -402,7 +405,7 @@ fn lex_split_shortflag_from_longflag(tokens: Vec<Token>) -> Vec<Token> {
|
||||
}
|
||||
//Currently the lexer does not split baselines on ',' ':' '?'
|
||||
//The parameter list requires this. Therefore here is a hacky method doing this.
|
||||
fn lex_split_baseline_tokens_on(
|
||||
pub fn lex_split_baseline_tokens_on(
|
||||
tokens: Vec<Token>,
|
||||
extra_baseline_terminal_tokens: &[char],
|
||||
) -> Vec<Token> {
|
||||
|
@ -19,11 +19,11 @@ fn simple_def_with_params() {
|
||||
sign.positional,
|
||||
vec![
|
||||
(
|
||||
PositionalType::Optional("param1".into(), SyntaxShape::Int),
|
||||
PositionalType::Optional("$param1".into(), SyntaxShape::Int),
|
||||
"".into()
|
||||
),
|
||||
(
|
||||
PositionalType::Mandatory("param2".into(), SyntaxShape::String),
|
||||
PositionalType::Mandatory("$param2".into(), SyntaxShape::String),
|
||||
"".into()
|
||||
),
|
||||
]
|
||||
@ -40,11 +40,11 @@ fn simple_def_with_optional_param_without_type() {
|
||||
sign.positional,
|
||||
vec![
|
||||
(
|
||||
PositionalType::Optional("param1".into(), SyntaxShape::Any),
|
||||
PositionalType::Optional("$param1".into(), SyntaxShape::Any),
|
||||
"".into()
|
||||
),
|
||||
(
|
||||
PositionalType::Optional("param2".into(), SyntaxShape::Any),
|
||||
PositionalType::Optional("$param2".into(), SyntaxShape::Any),
|
||||
"".into()
|
||||
),
|
||||
]
|
||||
@ -64,11 +64,11 @@ fn simple_def_with_params_with_comment() {
|
||||
sign.positional,
|
||||
vec![
|
||||
(
|
||||
PositionalType::Mandatory("param1".into(), SyntaxShape::FilePath),
|
||||
PositionalType::Mandatory("$param1".into(), SyntaxShape::FilePath),
|
||||
"My first param".into()
|
||||
),
|
||||
(
|
||||
PositionalType::Mandatory("param2".into(), SyntaxShape::Number),
|
||||
PositionalType::Mandatory("$param2".into(), SyntaxShape::Number),
|
||||
"My second param".into()
|
||||
),
|
||||
]
|
||||
@ -88,11 +88,11 @@ fn simple_def_with_params_without_type() {
|
||||
sign.positional,
|
||||
vec![
|
||||
(
|
||||
PositionalType::Mandatory("param1".into(), SyntaxShape::Any),
|
||||
PositionalType::Mandatory("$param1".into(), SyntaxShape::Any),
|
||||
"My first param".into()
|
||||
),
|
||||
(
|
||||
PositionalType::Mandatory("param2".into(), SyntaxShape::Number),
|
||||
PositionalType::Mandatory("$param2".into(), SyntaxShape::Number),
|
||||
"My second param".into()
|
||||
),
|
||||
]
|
||||
@ -116,23 +116,23 @@ fn oddly_but_correct_written_params() {
|
||||
sign.positional,
|
||||
vec![
|
||||
(
|
||||
PositionalType::Mandatory("param1".into(), SyntaxShape::Int),
|
||||
PositionalType::Mandatory("$param1".into(), SyntaxShape::Int),
|
||||
"param1".into()
|
||||
),
|
||||
(
|
||||
PositionalType::Mandatory("param2".into(), SyntaxShape::Number),
|
||||
PositionalType::Mandatory("$param2".into(), SyntaxShape::Number),
|
||||
"My second param".into()
|
||||
),
|
||||
(
|
||||
PositionalType::Mandatory("param4".into(), SyntaxShape::Any),
|
||||
PositionalType::Mandatory("$param4".into(), SyntaxShape::Any),
|
||||
"".into()
|
||||
),
|
||||
(
|
||||
PositionalType::Mandatory("param5".into(), SyntaxShape::FilePath),
|
||||
PositionalType::Mandatory("$param5".into(), SyntaxShape::FilePath),
|
||||
"".into()
|
||||
),
|
||||
(
|
||||
PositionalType::Mandatory("param6".into(), SyntaxShape::Any),
|
||||
PositionalType::Mandatory("$param6".into(), SyntaxShape::Any),
|
||||
"param6".into()
|
||||
),
|
||||
]
|
||||
@ -225,19 +225,19 @@ fn simple_def_with_params_and_flags() {
|
||||
sign.positional,
|
||||
vec![
|
||||
(
|
||||
PositionalType::Mandatory("param1".into(), SyntaxShape::Any),
|
||||
PositionalType::Mandatory("$param1".into(), SyntaxShape::Any),
|
||||
"".into()
|
||||
),
|
||||
(
|
||||
PositionalType::Mandatory("param2".into(), SyntaxShape::Table),
|
||||
PositionalType::Mandatory("$param2".into(), SyntaxShape::Table),
|
||||
"Param2 Doc".into()
|
||||
),
|
||||
(
|
||||
PositionalType::Mandatory("param3".into(), SyntaxShape::Number),
|
||||
PositionalType::Mandatory("$param3".into(), SyntaxShape::Number),
|
||||
"".into()
|
||||
),
|
||||
(
|
||||
PositionalType::Optional("param4".into(), SyntaxShape::Table),
|
||||
PositionalType::Optional("$param4".into(), SyntaxShape::Table),
|
||||
"Optional Param".into()
|
||||
),
|
||||
]
|
||||
@ -262,15 +262,15 @@ fn simple_def_with_parameters_and_flags_no_delimiter() {
|
||||
// --flag3 # Third flag
|
||||
vec![
|
||||
(
|
||||
PositionalType::Mandatory("param1".into(), SyntaxShape::Int),
|
||||
PositionalType::Mandatory("$param1".into(), SyntaxShape::Int),
|
||||
"".into()
|
||||
),
|
||||
(
|
||||
PositionalType::Mandatory("param2".into(), SyntaxShape::Any),
|
||||
PositionalType::Mandatory("$param2".into(), SyntaxShape::Any),
|
||||
"".into()
|
||||
),
|
||||
(
|
||||
PositionalType::Mandatory("param3".into(), SyntaxShape::Any),
|
||||
PositionalType::Mandatory("$param3".into(), SyntaxShape::Any),
|
||||
"Param3".into()
|
||||
),
|
||||
]
|
||||
@ -302,7 +302,7 @@ fn simple_example_signature() {
|
||||
assert_eq!(
|
||||
sign.positional,
|
||||
vec![(
|
||||
PositionalType::Mandatory("d".into(), SyntaxShape::Int),
|
||||
PositionalType::Mandatory("$d".into(), SyntaxShape::Int),
|
||||
"The required d parameter".into()
|
||||
)]
|
||||
);
|
||||
@ -374,7 +374,7 @@ fn simple_def_with_param_flag_and_rest() {
|
||||
assert_eq!(
|
||||
sign.positional,
|
||||
vec![(
|
||||
PositionalType::Mandatory("d".into(), SyntaxShape::String),
|
||||
PositionalType::Mandatory("$d".into(), SyntaxShape::String),
|
||||
"The required d parameter".into()
|
||||
)]
|
||||
);
|
||||
|
@ -28,7 +28,7 @@ pub fn expression_to_flat_shape(e: &SpannedExpression) -> Vec<Spanned<FlatShape>
|
||||
}
|
||||
output
|
||||
}
|
||||
Expression::Path(exprs) => {
|
||||
Expression::FullColumnPath(exprs) => {
|
||||
let mut output = vec![];
|
||||
output.append(&mut expression_to_flat_shape(&exprs.head));
|
||||
for member in exprs.tail.iter() {
|
||||
@ -119,6 +119,30 @@ pub fn shapes(commands: &Block) -> Vec<Spanned<FlatShape>> {
|
||||
ClassifiedCommand::Expr(expr) => {
|
||||
output.append(&mut expression_to_flat_shape(expr))
|
||||
}
|
||||
ClassifiedCommand::Dynamic(call) => {
|
||||
output.append(&mut expression_to_flat_shape(&call.head));
|
||||
|
||||
if let Some(positionals) = &call.positional {
|
||||
for positional_arg in positionals {
|
||||
output.append(&mut expression_to_flat_shape(positional_arg));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(named) = &call.named {
|
||||
for (_, named_arg) in named.iter() {
|
||||
match named_arg {
|
||||
NamedValue::PresentSwitch(span) => {
|
||||
output.push(FlatShape::Flag.spanned(*span));
|
||||
}
|
||||
NamedValue::Value(span, expr) => {
|
||||
output.push(FlatShape::Flag.spanned(*span));
|
||||
output.append(&mut expression_to_flat_shape(expr));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -315,10 +315,10 @@ impl ExternalCommand {
|
||||
pub fn has_it_usage(&self) -> bool {
|
||||
self.args.iter().any(|arg| match arg {
|
||||
SpannedExpression {
|
||||
expr: Expression::Path(path),
|
||||
expr: Expression::FullColumnPath(path),
|
||||
..
|
||||
} => {
|
||||
let Path { head, .. } = &**path;
|
||||
let FullColumnPath { head, .. } = &**path;
|
||||
matches!(head, SpannedExpression{expr: Expression::Variable(x, ..), ..} if x == "$it")
|
||||
}
|
||||
_ => false,
|
||||
@ -753,7 +753,7 @@ impl PrettyDebugWithSource for SpannedExpression {
|
||||
),
|
||||
"]",
|
||||
),
|
||||
Expression::Path(path) => path.pretty_debug(source),
|
||||
Expression::FullColumnPath(path) => path.pretty_debug(source),
|
||||
Expression::FilePath(path) => {
|
||||
DbgDocBldr::typed("path", DbgDocBldr::primitive(path.display()))
|
||||
}
|
||||
@ -808,7 +808,7 @@ impl PrettyDebugWithSource for SpannedExpression {
|
||||
),
|
||||
"]",
|
||||
),
|
||||
Expression::Path(path) => path.pretty_debug(source),
|
||||
Expression::FullColumnPath(path) => path.pretty_debug(source),
|
||||
Expression::FilePath(path) => {
|
||||
DbgDocBldr::typed("path", DbgDocBldr::primitive(path.display()))
|
||||
}
|
||||
@ -1006,12 +1006,12 @@ impl PrettyDebugWithSource for SpannedLiteral {
|
||||
}
|
||||
|
||||
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Clone, Hash, new, Deserialize, Serialize)]
|
||||
pub struct Path {
|
||||
pub struct FullColumnPath {
|
||||
pub head: SpannedExpression,
|
||||
pub tail: Vec<PathMember>,
|
||||
}
|
||||
|
||||
impl PrettyDebugWithSource for Path {
|
||||
impl PrettyDebugWithSource for FullColumnPath {
|
||||
fn pretty_debug(&self, source: &str) -> DebugDocBuilder {
|
||||
self.head.pretty_debug(source)
|
||||
+ DbgDocBldr::operator(".")
|
||||
@ -1033,7 +1033,7 @@ pub enum Expression {
|
||||
Block(Arc<hir::Block>),
|
||||
List(Vec<SpannedExpression>),
|
||||
Table(Vec<SpannedExpression>, Vec<Vec<SpannedExpression>>),
|
||||
Path(Box<Path>),
|
||||
FullColumnPath(Box<FullColumnPath>),
|
||||
|
||||
FilePath(PathBuf),
|
||||
ExternalCommand(ExternalStringCommand),
|
||||
@ -1063,7 +1063,7 @@ impl ShellTypeName for Expression {
|
||||
Expression::Range(..) => "range",
|
||||
Expression::Block(..) => "block",
|
||||
Expression::Invocation(..) => "command invocation",
|
||||
Expression::Path(..) => "variable path",
|
||||
Expression::FullColumnPath(..) => "variable path",
|
||||
Expression::Boolean(..) => "boolean",
|
||||
Expression::ExternalCommand(..) => "external",
|
||||
Expression::Garbage => "garbage",
|
||||
@ -1129,7 +1129,7 @@ impl Expression {
|
||||
|
||||
pub fn path(head: SpannedExpression, tail: Vec<impl Into<PathMember>>) -> Expression {
|
||||
let tail = tail.into_iter().map(|t| t.into()).collect();
|
||||
Expression::Path(Box::new(Path::new(head, tail)))
|
||||
Expression::FullColumnPath(Box::new(FullColumnPath::new(head, tail)))
|
||||
}
|
||||
|
||||
pub fn unit(i: Spanned<i64>, unit: Spanned<Unit>) -> Expression {
|
||||
@ -1157,7 +1157,7 @@ impl Expression {
|
||||
Expression::List(list) => list.iter().any(|se| se.has_it_usage()),
|
||||
Expression::Invocation(block) => block.has_it_usage(),
|
||||
Expression::Binary(binary) => binary.left.has_it_usage() || binary.right.has_it_usage(),
|
||||
Expression::Path(path) => path.head.has_it_usage(),
|
||||
Expression::FullColumnPath(path) => path.head.has_it_usage(),
|
||||
Expression::Range(range) => {
|
||||
(if let Some(left) = &range.left {
|
||||
left.has_it_usage()
|
||||
@ -1203,7 +1203,7 @@ impl Expression {
|
||||
output.extend(binary.left.get_free_variables(known_variables));
|
||||
output.extend(binary.right.get_free_variables(known_variables));
|
||||
}
|
||||
Expression::Path(path) => {
|
||||
Expression::FullColumnPath(path) => {
|
||||
output.extend(path.head.get_free_variables(known_variables));
|
||||
}
|
||||
Expression::Range(range) => {
|
||||
|
Loading…
Reference in New Issue
Block a user