Add explicit block params (#3444)

* Add explicit block params

* Add explicit block params
This commit is contained in:
JT 2021-05-19 20:23:45 +12:00 committed by GitHub
parent 0ff08bb63a
commit e2973d2176
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 153 additions and 57 deletions

View File

@ -37,7 +37,7 @@ impl<'s> Flatten<'s> {
) )
.collect(), .collect(),
Expression::Command => vec![LocationType::Command.spanned(e.span)], 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::Variable(_, _) => vec![LocationType::Variable.spanned(e.span)],
Expression::Boolean(_) Expression::Boolean(_)

View File

@ -296,7 +296,7 @@ fn get_shape_of_expr(expr: &SpannedExpression) -> Option<SyntaxShape> {
Expression::List(_) => Some(SyntaxShape::Table), Expression::List(_) => Some(SyntaxShape::Table),
Expression::Boolean(_) => Some(SyntaxShape::String), Expression::Boolean(_) => Some(SyntaxShape::String),
Expression::Path(_) => Some(SyntaxShape::ColumnPath), Expression::FullColumnPath(_) => Some(SyntaxShape::ColumnPath),
Expression::FilePath(_) => Some(SyntaxShape::FilePath), Expression::FilePath(_) => Some(SyntaxShape::FilePath),
Expression::Block(_) => Some(SyntaxShape::Block), Expression::Block(_) => Some(SyntaxShape::Block),
Expression::ExternalCommand(_) => Some(SyntaxShape::String), Expression::ExternalCommand(_) => Some(SyntaxShape::String),
@ -539,7 +539,7 @@ impl VarSyntaxShapeDeductor {
trace!("Inferring vars in block"); trace!("Inferring vars in block");
self.infer_shape(&b, scope)?; self.infer_shape(&b, scope)?;
} }
Expression::Path(path) => { Expression::FullColumnPath(path) => {
trace!("Inferring vars in path"); trace!("Inferring vars in path");
match &path.head.expr { match &path.head.expr {
//PathMember can't be var yet (?) //PathMember can't be var yet (?)
@ -790,7 +790,7 @@ impl VarSyntaxShapeDeductor {
| Expression::Binary(_) | Expression::Binary(_)
| Expression::Range(_) | Expression::Range(_)
| Expression::Block(_) | Expression::Block(_)
| Expression::Path(_) | Expression::FullColumnPath(_)
| Expression::FilePath(_) | Expression::FilePath(_)
| Expression::ExternalCommand(_) | Expression::ExternalCommand(_)
| Expression::Command | Expression::Command

View File

@ -55,6 +55,15 @@ impl WholeStreamCommand for Each {
"echo ['bob' 'fred'] | each --numbered { echo $\"{$it.index} is {$it.item}\" }", "echo ['bob' 'fred'] | each --numbered { echo $\"{$it.index} is {$it.item}\" }",
result: Some(vec![Value::from("0 is bob"), Value::from("1 is fred")]), 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(),
]),
},
] ]
} }
} }

View File

@ -159,7 +159,7 @@ pub fn evaluate_baseline_expr(
.into_value(&tag), .into_value(&tag),
) )
} }
Expression::Path(path) => { Expression::FullColumnPath(path) => {
let value = evaluate_baseline_expr(&path.head, ctx)?; let value = evaluate_baseline_expr(&path.head, ctx)?;
let mut item = value; let mut item = value;

View File

@ -13,12 +13,18 @@ use nu_protocol::{NamedType, PositionalType, Signature, SyntaxShape, UnspannedPa
use nu_source::{HasSpan, Span, Spanned, SpannedItem}; use nu_source::{HasSpan, Span, Spanned, SpannedItem};
use num_bigint::BigInt; use num_bigint::BigInt;
use crate::lex::tokens::{LiteBlock, LiteCommand, LitePipeline};
use crate::path::expand_path;
use crate::{ use crate::{
lex::lexer::{lex, parse_block}, lex::lexer::{lex, parse_block},
ParserScope, 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::{ use self::{
def::{parse_definition, parse_definition_prototype}, def::{parse_definition, parse_definition_prototype},
@ -919,20 +925,78 @@ fn parse_arg(
let string: String = chars.collect(); let string: String = chars.collect();
// We haven't done much with the inner string, so let's go ahead and work with it // 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() { if err.is_some() {
return (garbage(lite_arg.span), err); 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); let (lite_block, err) = parse_block(tokens);
if err.is_some() { if err.is_some() {
return (garbage(lite_arg.span), err); return (garbage(lite_arg.span), err);
} }
scope.enter_scope(); 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(); 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), SpannedExpression::new(Expression::Block(classified_block), lite_arg.span),
err, err,
@ -1600,16 +1664,11 @@ fn parse_call(
})), })),
error, 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('{') { } else if lite_cmd.parts[0].item.starts_with('{') {
return parse_value_call(lite_cmd, scope); return parse_value_call(lite_cmd, scope);
} else if lite_cmd.parts[0].item.starts_with('$') } 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('`')
|| 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('0')
|| lite_cmd.parts[0].item.starts_with('1') || lite_cmd.parts[0].item.starts_with('1')

View File

@ -16,6 +16,7 @@ use crate::lex::lexer::{lex, parse_block};
use crate::ParserScope; use crate::ParserScope;
use self::signature::parse_signature; use self::signature::parse_signature;
pub use self::signature::{lex_split_baseline_tokens_on, parse_parameter};
mod data_structs; mod data_structs;
mod primitives; mod primitives;

View File

@ -87,7 +87,7 @@ pub fn parse_signature(
i += advanced_by; i += advanced_by;
rest = rest_; rest = rest_;
} else { } 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); err = err.or(error);
i += advanced_by; i += advanced_by;
parameters.push(parameter); parameters.push(parameter);
@ -100,16 +100,13 @@ pub fn parse_signature(
(signature, err) (signature, err)
} }
fn parse_parameter( pub fn parse_parameter(tokens: &[Token], span: Span) -> (Parameter, usize, Option<ParseError>) {
tokens: &[Token],
tokens_as_str: &Spanned<String>,
) -> (Parameter, usize, Option<ParseError>) {
if tokens.is_empty() { if tokens.is_empty() {
//TODO fix span //TODO fix span
return ( return (
Parameter::error(), Parameter::error(),
0, 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 { let pos_type = if optional {
if name.item.starts_with('$') {
PositionalType::optional(&name.item, type_) PositionalType::optional(&name.item, type_)
} else { } else {
PositionalType::optional(&format!("${}", name.item), type_)
}
} else if name.item.starts_with('$') {
PositionalType::mandatory(&name.item, type_) PositionalType::mandatory(&name.item, type_)
} else {
PositionalType::mandatory(&format!("${}", name.item), type_)
}; };
let parameter = Parameter::new(pos_type, comment, name.span); 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 ',' ':' '?' //Currently the lexer does not split baselines on ',' ':' '?'
//The parameter list requires this. Therefore here is a hacky method doing this. //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>, tokens: Vec<Token>,
extra_baseline_terminal_tokens: &[char], extra_baseline_terminal_tokens: &[char],
) -> Vec<Token> { ) -> Vec<Token> {

View File

@ -19,11 +19,11 @@ fn simple_def_with_params() {
sign.positional, sign.positional,
vec![ vec![
( (
PositionalType::Optional("param1".into(), SyntaxShape::Int), PositionalType::Optional("$param1".into(), SyntaxShape::Int),
"".into() "".into()
), ),
( (
PositionalType::Mandatory("param2".into(), SyntaxShape::String), PositionalType::Mandatory("$param2".into(), SyntaxShape::String),
"".into() "".into()
), ),
] ]
@ -40,11 +40,11 @@ fn simple_def_with_optional_param_without_type() {
sign.positional, sign.positional,
vec![ vec![
( (
PositionalType::Optional("param1".into(), SyntaxShape::Any), PositionalType::Optional("$param1".into(), SyntaxShape::Any),
"".into() "".into()
), ),
( (
PositionalType::Optional("param2".into(), SyntaxShape::Any), PositionalType::Optional("$param2".into(), SyntaxShape::Any),
"".into() "".into()
), ),
] ]
@ -64,11 +64,11 @@ fn simple_def_with_params_with_comment() {
sign.positional, sign.positional,
vec![ vec![
( (
PositionalType::Mandatory("param1".into(), SyntaxShape::FilePath), PositionalType::Mandatory("$param1".into(), SyntaxShape::FilePath),
"My first param".into() "My first param".into()
), ),
( (
PositionalType::Mandatory("param2".into(), SyntaxShape::Number), PositionalType::Mandatory("$param2".into(), SyntaxShape::Number),
"My second param".into() "My second param".into()
), ),
] ]
@ -88,11 +88,11 @@ fn simple_def_with_params_without_type() {
sign.positional, sign.positional,
vec![ vec![
( (
PositionalType::Mandatory("param1".into(), SyntaxShape::Any), PositionalType::Mandatory("$param1".into(), SyntaxShape::Any),
"My first param".into() "My first param".into()
), ),
( (
PositionalType::Mandatory("param2".into(), SyntaxShape::Number), PositionalType::Mandatory("$param2".into(), SyntaxShape::Number),
"My second param".into() "My second param".into()
), ),
] ]
@ -116,23 +116,23 @@ fn oddly_but_correct_written_params() {
sign.positional, sign.positional,
vec![ vec![
( (
PositionalType::Mandatory("param1".into(), SyntaxShape::Int), PositionalType::Mandatory("$param1".into(), SyntaxShape::Int),
"param1".into() "param1".into()
), ),
( (
PositionalType::Mandatory("param2".into(), SyntaxShape::Number), PositionalType::Mandatory("$param2".into(), SyntaxShape::Number),
"My second param".into() "My second param".into()
), ),
( (
PositionalType::Mandatory("param4".into(), SyntaxShape::Any), PositionalType::Mandatory("$param4".into(), SyntaxShape::Any),
"".into() "".into()
), ),
( (
PositionalType::Mandatory("param5".into(), SyntaxShape::FilePath), PositionalType::Mandatory("$param5".into(), SyntaxShape::FilePath),
"".into() "".into()
), ),
( (
PositionalType::Mandatory("param6".into(), SyntaxShape::Any), PositionalType::Mandatory("$param6".into(), SyntaxShape::Any),
"param6".into() "param6".into()
), ),
] ]
@ -225,19 +225,19 @@ fn simple_def_with_params_and_flags() {
sign.positional, sign.positional,
vec![ vec![
( (
PositionalType::Mandatory("param1".into(), SyntaxShape::Any), PositionalType::Mandatory("$param1".into(), SyntaxShape::Any),
"".into() "".into()
), ),
( (
PositionalType::Mandatory("param2".into(), SyntaxShape::Table), PositionalType::Mandatory("$param2".into(), SyntaxShape::Table),
"Param2 Doc".into() "Param2 Doc".into()
), ),
( (
PositionalType::Mandatory("param3".into(), SyntaxShape::Number), PositionalType::Mandatory("$param3".into(), SyntaxShape::Number),
"".into() "".into()
), ),
( (
PositionalType::Optional("param4".into(), SyntaxShape::Table), PositionalType::Optional("$param4".into(), SyntaxShape::Table),
"Optional Param".into() "Optional Param".into()
), ),
] ]
@ -262,15 +262,15 @@ fn simple_def_with_parameters_and_flags_no_delimiter() {
// --flag3 # Third flag // --flag3 # Third flag
vec![ vec![
( (
PositionalType::Mandatory("param1".into(), SyntaxShape::Int), PositionalType::Mandatory("$param1".into(), SyntaxShape::Int),
"".into() "".into()
), ),
( (
PositionalType::Mandatory("param2".into(), SyntaxShape::Any), PositionalType::Mandatory("$param2".into(), SyntaxShape::Any),
"".into() "".into()
), ),
( (
PositionalType::Mandatory("param3".into(), SyntaxShape::Any), PositionalType::Mandatory("$param3".into(), SyntaxShape::Any),
"Param3".into() "Param3".into()
), ),
] ]
@ -302,7 +302,7 @@ fn simple_example_signature() {
assert_eq!( assert_eq!(
sign.positional, sign.positional,
vec![( vec![(
PositionalType::Mandatory("d".into(), SyntaxShape::Int), PositionalType::Mandatory("$d".into(), SyntaxShape::Int),
"The required d parameter".into() "The required d parameter".into()
)] )]
); );
@ -374,7 +374,7 @@ fn simple_def_with_param_flag_and_rest() {
assert_eq!( assert_eq!(
sign.positional, sign.positional,
vec![( vec![(
PositionalType::Mandatory("d".into(), SyntaxShape::String), PositionalType::Mandatory("$d".into(), SyntaxShape::String),
"The required d parameter".into() "The required d parameter".into()
)] )]
); );

View File

@ -28,7 +28,7 @@ pub fn expression_to_flat_shape(e: &SpannedExpression) -> Vec<Spanned<FlatShape>
} }
output output
} }
Expression::Path(exprs) => { Expression::FullColumnPath(exprs) => {
let mut output = vec![]; let mut output = vec![];
output.append(&mut expression_to_flat_shape(&exprs.head)); output.append(&mut expression_to_flat_shape(&exprs.head));
for member in exprs.tail.iter() { for member in exprs.tail.iter() {
@ -119,6 +119,30 @@ pub fn shapes(commands: &Block) -> Vec<Spanned<FlatShape>> {
ClassifiedCommand::Expr(expr) => { ClassifiedCommand::Expr(expr) => {
output.append(&mut expression_to_flat_shape(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));
}
_ => {}
}
}
}
}
_ => {} _ => {}
} }
} }

View File

@ -315,10 +315,10 @@ impl ExternalCommand {
pub fn has_it_usage(&self) -> bool { pub fn has_it_usage(&self) -> bool {
self.args.iter().any(|arg| match arg { self.args.iter().any(|arg| match arg {
SpannedExpression { 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") matches!(head, SpannedExpression{expr: Expression::Variable(x, ..), ..} if x == "$it")
} }
_ => false, _ => 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) => { Expression::FilePath(path) => {
DbgDocBldr::typed("path", DbgDocBldr::primitive(path.display())) 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) => { Expression::FilePath(path) => {
DbgDocBldr::typed("path", DbgDocBldr::primitive(path.display())) 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)] #[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Clone, Hash, new, Deserialize, Serialize)]
pub struct Path { pub struct FullColumnPath {
pub head: SpannedExpression, pub head: SpannedExpression,
pub tail: Vec<PathMember>, pub tail: Vec<PathMember>,
} }
impl PrettyDebugWithSource for Path { impl PrettyDebugWithSource for FullColumnPath {
fn pretty_debug(&self, source: &str) -> DebugDocBuilder { fn pretty_debug(&self, source: &str) -> DebugDocBuilder {
self.head.pretty_debug(source) self.head.pretty_debug(source)
+ DbgDocBldr::operator(".") + DbgDocBldr::operator(".")
@ -1033,7 +1033,7 @@ pub enum Expression {
Block(Arc<hir::Block>), Block(Arc<hir::Block>),
List(Vec<SpannedExpression>), List(Vec<SpannedExpression>),
Table(Vec<SpannedExpression>, Vec<Vec<SpannedExpression>>), Table(Vec<SpannedExpression>, Vec<Vec<SpannedExpression>>),
Path(Box<Path>), FullColumnPath(Box<FullColumnPath>),
FilePath(PathBuf), FilePath(PathBuf),
ExternalCommand(ExternalStringCommand), ExternalCommand(ExternalStringCommand),
@ -1063,7 +1063,7 @@ impl ShellTypeName for Expression {
Expression::Range(..) => "range", Expression::Range(..) => "range",
Expression::Block(..) => "block", Expression::Block(..) => "block",
Expression::Invocation(..) => "command invocation", Expression::Invocation(..) => "command invocation",
Expression::Path(..) => "variable path", Expression::FullColumnPath(..) => "variable path",
Expression::Boolean(..) => "boolean", Expression::Boolean(..) => "boolean",
Expression::ExternalCommand(..) => "external", Expression::ExternalCommand(..) => "external",
Expression::Garbage => "garbage", Expression::Garbage => "garbage",
@ -1129,7 +1129,7 @@ impl Expression {
pub fn path(head: SpannedExpression, tail: Vec<impl Into<PathMember>>) -> Expression { pub fn path(head: SpannedExpression, tail: Vec<impl Into<PathMember>>) -> Expression {
let tail = tail.into_iter().map(|t| t.into()).collect(); 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 { 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::List(list) => list.iter().any(|se| se.has_it_usage()),
Expression::Invocation(block) => block.has_it_usage(), Expression::Invocation(block) => block.has_it_usage(),
Expression::Binary(binary) => binary.left.has_it_usage() || binary.right.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) => { Expression::Range(range) => {
(if let Some(left) = &range.left { (if let Some(left) = &range.left {
left.has_it_usage() left.has_it_usage()
@ -1203,7 +1203,7 @@ impl Expression {
output.extend(binary.left.get_free_variables(known_variables)); output.extend(binary.left.get_free_variables(known_variables));
output.extend(binary.right.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)); output.extend(path.head.get_free_variables(known_variables));
} }
Expression::Range(range) => { Expression::Range(range) => {