From 32c1f0c8d40e1d0aad78c5d5963a30dfc0d595f6 Mon Sep 17 00:00:00 2001 From: JT Date: Mon, 13 Sep 2021 19:54:13 +1200 Subject: [PATCH] better it detection and block params in shapes --- crates/nu-command/src/benchmark.rs | 6 +++- crates/nu-command/src/def.rs | 6 +++- crates/nu-command/src/do_.rs | 6 +++- crates/nu-command/src/each.rs | 6 +++- crates/nu-command/src/for_.rs | 6 +++- crates/nu-command/src/if_.rs | 2 +- crates/nu-parser/src/parser.rs | 50 ++++++++++++++------------ crates/nu-protocol/src/syntax_shape.rs | 4 +-- src/tests.rs | 8 +++++ 9 files changed, 64 insertions(+), 30 deletions(-) diff --git a/crates/nu-command/src/benchmark.rs b/crates/nu-command/src/benchmark.rs index 5bd5a6afcc..1590e8af84 100644 --- a/crates/nu-command/src/benchmark.rs +++ b/crates/nu-command/src/benchmark.rs @@ -17,7 +17,11 @@ impl Command for Benchmark { } fn signature(&self) -> nu_protocol::Signature { - Signature::build("benchmark").required("block", SyntaxShape::Block, "the block to run") + Signature::build("benchmark").required( + "block", + SyntaxShape::Block(Some(vec![])), + "the block to run", + ) } fn run( diff --git a/crates/nu-command/src/def.rs b/crates/nu-command/src/def.rs index 25004d800d..0f6ef1b56b 100644 --- a/crates/nu-command/src/def.rs +++ b/crates/nu-command/src/def.rs @@ -17,7 +17,11 @@ impl Command for Def { Signature::build("def") .required("def_name", SyntaxShape::String, "definition name") .required("params", SyntaxShape::Signature, "parameters") - .required("block", SyntaxShape::Block, "body of the definition") + .required( + "block", + SyntaxShape::Block(Some(vec![])), + "body of the definition", + ) } fn run( diff --git a/crates/nu-command/src/do_.rs b/crates/nu-command/src/do_.rs index 3630e84ff6..20bd0eb7d2 100644 --- a/crates/nu-command/src/do_.rs +++ b/crates/nu-command/src/do_.rs @@ -15,7 +15,11 @@ impl Command for Do { } fn signature(&self) -> nu_protocol::Signature { - Signature::build("do").required("block", SyntaxShape::Block, "the block to run") + Signature::build("do").required( + "block", + SyntaxShape::Block(Some(vec![])), + "the block to run", + ) } fn run( diff --git a/crates/nu-command/src/each.rs b/crates/nu-command/src/each.rs index 109b082f1f..e48cfb719a 100644 --- a/crates/nu-command/src/each.rs +++ b/crates/nu-command/src/each.rs @@ -16,7 +16,11 @@ impl Command for Each { fn signature(&self) -> nu_protocol::Signature { Signature::build("each") - .required("block", SyntaxShape::Block, "the block to run") + .required( + "block", + SyntaxShape::Block(Some(vec![SyntaxShape::Any])), + "the block to run", + ) .switch("numbered", "iterate with an index", Some('n')) } diff --git a/crates/nu-command/src/for_.rs b/crates/nu-command/src/for_.rs index 35d806dd56..158cd6b6c8 100644 --- a/crates/nu-command/src/for_.rs +++ b/crates/nu-command/src/for_.rs @@ -29,7 +29,11 @@ impl Command for For { ), "range of the loop", ) - .required("block", SyntaxShape::Block, "the block to run") + .required( + "block", + SyntaxShape::Block(Some(vec![])), + "the block to run", + ) } fn run( diff --git a/crates/nu-command/src/if_.rs b/crates/nu-command/src/if_.rs index 2b8df48671..a9b1489a66 100644 --- a/crates/nu-command/src/if_.rs +++ b/crates/nu-command/src/if_.rs @@ -17,7 +17,7 @@ impl Command for If { fn signature(&self) -> nu_protocol::Signature { Signature::build("if") .required("cond", SyntaxShape::Expression, "condition") - .required("then_block", SyntaxShape::Block, "then block") + .required("then_block", SyntaxShape::Block(Some(vec![])), "then block") .optional( "else", SyntaxShape::Keyword(b"else".to_vec(), Box::new(SyntaxShape::Expression)), diff --git a/crates/nu-parser/src/parser.rs b/crates/nu-parser/src/parser.rs index 7a7c09db98..d1dada0fb9 100644 --- a/crates/nu-parser/src/parser.rs +++ b/crates/nu-parser/src/parser.rs @@ -1030,20 +1030,7 @@ pub fn parse_variable_expr( None, ) } else { - // let name = working_set.get_span_contents(span).to_vec(); - // this seems okay to set it to unknown here, but we should double-check - //let id = working_set.add_variable(name, Type::Unknown); - // ( - // Expression { - // expr: Expr::Var(id), - // span, - // ty: Type::Unknown, - // }, - // None, - // ) - // } else { - (garbage(span), err) - // } + (garbage(span), Some(ParseError::VariableNotFound(span))) } } else { (garbage(span), err) @@ -1243,7 +1230,7 @@ pub fn parse_shape_name( b"int" => SyntaxShape::Int, b"path" => SyntaxShape::FilePath, b"glob" => SyntaxShape::GlobPattern, - b"block" => SyntaxShape::Block, + b"block" => SyntaxShape::Block(None), //FIXME b"cond" => SyntaxShape::RowCondition, b"operator" => SyntaxShape::Operator, b"math" => SyntaxShape::MathExpression, @@ -1905,6 +1892,7 @@ pub fn parse_table_expression( pub fn parse_block_expression( working_set: &mut StateWorkingSet, + shape: &SyntaxShape, span: Span, ) -> (Expression, Option) { let bytes = working_set.get_span_contents(span); @@ -1945,7 +1933,7 @@ pub fn parse_block_expression( working_set.enter_scope(); // Check to see if we have parameters - let (signature, amt_to_skip): (Option>, usize) = match output.first() { + let (mut signature, amt_to_skip): (Option>, usize) = match output.first() { Some(Token { contents: TokenContents::Pipe, span, @@ -1991,6 +1979,23 @@ pub fn parse_block_expression( let (output, err) = lite_parse(&output[amt_to_skip..]); error = error.or(err); + if let SyntaxShape::Block(Some(v)) = shape { + if signature.is_none() && v.len() == 1 { + // We'll assume there's an `$it` present + let var_id = working_set.add_variable(b"$it".to_vec(), Type::Unknown); + + let mut new_sigature = Signature::new(""); + new_sigature.required_positional.push(PositionalArg { + var_id: Some(var_id), + name: "$it".into(), + desc: String::new(), + shape: SyntaxShape::Any, + }); + + signature = Some(Box::new(new_sigature)); + } + } + let (mut output, err) = parse_block(working_set, &output, false); error = error.or(err); @@ -2049,8 +2054,8 @@ pub fn parse_value( return parse_full_column_path(working_set, None, span); } } else if bytes.starts_with(b"{") { - if matches!(shape, SyntaxShape::Block) || matches!(shape, SyntaxShape::Any) { - return parse_block_expression(working_set, span); + if matches!(shape, SyntaxShape::Block(_)) || matches!(shape, SyntaxShape::Any) { + return parse_block_expression(working_set, shape, span); } else { return ( Expression::garbage(span), @@ -2079,9 +2084,9 @@ pub fn parse_value( SyntaxShape::String | SyntaxShape::GlobPattern | SyntaxShape::FilePath => { parse_string(working_set, span) } - SyntaxShape::Block => { + SyntaxShape::Block(_) => { if bytes.starts_with(b"{") { - parse_block_expression(working_set, span) + parse_block_expression(working_set, shape, span) } else { ( Expression::garbage(span), @@ -2129,7 +2134,7 @@ pub fn parse_value( SyntaxShape::Range, SyntaxShape::Filesize, SyntaxShape::Duration, - SyntaxShape::Block, + SyntaxShape::Block(None), SyntaxShape::String, ]; for shape in shapes.iter() { @@ -2381,7 +2386,8 @@ pub fn parse_def( let (sig, err) = parse_signature(working_set, spans[2]); error = error.or(err); - let (block, err) = parse_block_expression(working_set, spans[3]); + let (block, err) = + parse_block_expression(working_set, &SyntaxShape::Block(Some(vec![])), spans[3]); error = error.or(err); working_set.exit_scope(); diff --git a/crates/nu-protocol/src/syntax_shape.rs b/crates/nu-protocol/src/syntax_shape.rs index bee2450a8a..b5b81fe9ab 100644 --- a/crates/nu-protocol/src/syntax_shape.rs +++ b/crates/nu-protocol/src/syntax_shape.rs @@ -34,7 +34,7 @@ pub enum SyntaxShape { GlobPattern, /// A block is allowed, eg `{start this thing}` - Block(Vec<(Vec, SyntaxShape)>), + Block(Option>), /// A table is allowed, eg `[[first, second]; [1, 2]]` Table, @@ -75,7 +75,7 @@ impl SyntaxShape { pub fn to_type(&self) -> Type { match self { SyntaxShape::Any => Type::Unknown, - SyntaxShape::Block => Type::Block, + SyntaxShape::Block(_) => Type::Block, SyntaxShape::CellPath => Type::Unknown, SyntaxShape::Duration => Type::Duration, SyntaxShape::Expression => Type::Unknown, diff --git a/src/tests.rs b/src/tests.rs index df619f2b91..8684e817b7 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -308,3 +308,11 @@ fn row_condition2() -> TestResult { "1", ) } + +#[test] +fn better_block_types() -> TestResult { + run_test( + r#"([1, 2, 3] | each -n { $"($it.index) is ($it.item)" }).1"#, + "1 is 2", + ) +}