From 56b3fc61a3dac5507b49b70dc272a8032428ebe1 Mon Sep 17 00:00:00 2001 From: JT <547158+jntrnr@users.noreply.github.com> Date: Tue, 15 Feb 2022 14:31:14 -0500 Subject: [PATCH] Remove statements, replaced by pipelines (#4482) --- crates/nu-cli/src/completions.rs | 438 ++++++++++----------- crates/nu-engine/src/eval.rs | 46 +-- crates/nu-parser/src/errors.rs | 6 +- crates/nu-parser/src/flatten.rs | 18 +- crates/nu-parser/src/lib.rs | 4 +- crates/nu-parser/src/lite_parse.rs | 16 +- crates/nu-parser/src/parse_keywords.rs | 252 ++++++------ crates/nu-parser/src/parser.rs | 122 +++--- crates/nu-parser/tests/test_lite_parser.rs | 2 +- crates/nu-parser/tests/test_parser.rs | 414 +++++++++---------- crates/nu-protocol/src/ast/block.rs | 22 +- crates/nu-protocol/src/ast/expression.rs | 30 +- crates/nu-protocol/src/ast/mod.rs | 2 - crates/nu-protocol/src/ast/pipeline.rs | 24 ++ crates/nu-protocol/src/ast/statement.rs | 8 - src/main.rs | 6 +- 16 files changed, 660 insertions(+), 750 deletions(-) delete mode 100644 crates/nu-protocol/src/ast/statement.rs diff --git a/crates/nu-cli/src/completions.rs b/crates/nu-cli/src/completions.rs index 6da9eaffb0..7891ec9ac5 100644 --- a/crates/nu-cli/src/completions.rs +++ b/crates/nu-cli/src/completions.rs @@ -1,7 +1,7 @@ use nu_engine::eval_block; use nu_parser::{flatten_expression, parse, trim_quotes, FlatShape}; use nu_protocol::{ - ast::{Expr, Statement}, + ast::Expr, engine::{EngineState, Stack, StateWorkingSet}, PipelineData, Span, Value, CONFIG_VARIABLE_ID, }; @@ -174,228 +174,214 @@ impl NuCompleter { let pos = offset + pos; let (output, _err) = parse(&mut working_set, Some("completer"), line.as_bytes(), false); - for stmt in output.stmts.into_iter() { - if let Statement::Pipeline(pipeline) = stmt { - for expr in pipeline.expressions { - let flattened: Vec<_> = flatten_expression(&working_set, &expr); + for pipeline in output.pipelines.into_iter() { + for expr in pipeline.expressions { + let flattened: Vec<_> = flatten_expression(&working_set, &expr); - for (flat_idx, flat) in flattened.iter().enumerate() { - if pos >= flat.0.start && pos < flat.0.end { - let new_span = Span { - start: flat.0.start, - end: flat.0.end - 1, - }; + for (flat_idx, flat) in flattened.iter().enumerate() { + if pos >= flat.0.start && pos < flat.0.end { + let new_span = Span { + start: flat.0.start, + end: flat.0.end - 1, + }; - let mut prefix = working_set.get_span_contents(flat.0).to_vec(); - prefix.remove(pos - flat.0.start); + let mut prefix = working_set.get_span_contents(flat.0).to_vec(); + prefix.remove(pos - flat.0.start); - if prefix.starts_with(b"$") { - return self.complete_variables( - &working_set, - &prefix, - new_span, - offset, - ); - } - if prefix.starts_with(b"-") { - // this might be a flag, let's see - if let Expr::Call(call) = &expr.expr { - let decl = working_set.get_decl(call.decl_id); - let sig = decl.signature(); + if prefix.starts_with(b"$") { + return self.complete_variables( + &working_set, + &prefix, + new_span, + offset, + ); + } + if prefix.starts_with(b"-") { + // this might be a flag, let's see + if let Expr::Call(call) = &expr.expr { + let decl = working_set.get_decl(call.decl_id); + let sig = decl.signature(); - let mut output = vec![]; + let mut output = vec![]; - for named in &sig.named { - let mut named = named.long.as_bytes().to_vec(); - named.insert(0, b'-'); - named.insert(0, b'-'); - if named.starts_with(&prefix) { - output.push(( - reedline::Span { - start: new_span.start - offset, - end: new_span.end - offset, - }, - String::from_utf8_lossy(&named).to_string(), - )); - } - } - return output; - } - } - - match &flat.1 { - FlatShape::Custom(custom_completion) => { - //let prefix = working_set.get_span_contents(flat.0).to_vec(); - - let (block, ..) = parse( - &mut working_set, - None, - custom_completion.as_bytes(), - false, - ); - - let mut stack = Stack::new(); - // Set up our initial config to start from - stack.vars.insert( - CONFIG_VARIABLE_ID, - Value::Record { - cols: vec![], - vals: vec![], - span: Span { start: 0, end: 0 }, - }, - ); - let result = eval_block( - &self.engine_state, - &mut stack, - &block, - PipelineData::new(new_span), - ); - - let v: Vec<_> = match result { - Ok(pd) => pd - .into_iter() - .filter_map(move |x| { - let s = x.as_string(); - - match s { - Ok(s) => Some(( - reedline::Span { - start: new_span.start - offset, - end: new_span.end - offset, - }, - s, - )), - Err(_) => None, - } - }) - .filter(|x| x.1.as_bytes().starts_with(&prefix)) - .collect(), - _ => vec![], - }; - - return v; - } - FlatShape::Filepath | FlatShape::GlobPattern => { - let cwd = if let Some(d) = self.engine_state.env_vars.get("PWD") - { - match d.as_string() { - Ok(s) => s, - Err(_) => "".to_string(), - } - } else { - "".to_string() - }; - let prefix = String::from_utf8_lossy(&prefix).to_string(); - return file_path_completion(new_span, &prefix, &cwd) - .into_iter() - .map(move |x| { - ( - reedline::Span { - start: x.0.start - offset, - end: x.0.end - offset, - }, - x.1, - ) - }) - .collect(); - } - flat_shape => { - let last = flattened - .iter() - .rev() - .skip_while(|x| x.0.end > pos) - .take_while(|x| { - matches!( - x.1, - FlatShape::InternalCall - | FlatShape::External - | FlatShape::ExternalArg - | FlatShape::Literal - | FlatShape::String - ) - }) - .last(); - - // The last item here would be the earliest shape that could possible by part of this subcommand - let subcommands = if let Some(last) = last { - self.complete_commands( - &working_set, - Span { - start: last.0.start, - end: pos, + for named in &sig.named { + let mut named = named.long.as_bytes().to_vec(); + named.insert(0, b'-'); + named.insert(0, b'-'); + if named.starts_with(&prefix) { + output.push(( + reedline::Span { + start: new_span.start - offset, + end: new_span.end - offset, }, - offset, - false, - ) - } else { - vec![] - }; - - if !subcommands.is_empty() { - return subcommands; + String::from_utf8_lossy(&named).to_string(), + )); } + } + return output; + } + } - let commands = - if matches!(flat_shape, nu_parser::FlatShape::External) - || matches!( - flat_shape, - nu_parser::FlatShape::InternalCall - ) - || ((new_span.end - new_span.start) == 0) - { - // we're in a gap or at a command - self.complete_commands( - &working_set, - new_span, - offset, - true, - ) - } else { - vec![] - }; + match &flat.1 { + FlatShape::Custom(custom_completion) => { + //let prefix = working_set.get_span_contents(flat.0).to_vec(); - let cwd = if let Some(d) = self.engine_state.env_vars.get("PWD") + let (block, ..) = parse( + &mut working_set, + None, + custom_completion.as_bytes(), + false, + ); + + let mut stack = Stack::new(); + // Set up our initial config to start from + stack.vars.insert( + CONFIG_VARIABLE_ID, + Value::Record { + cols: vec![], + vals: vec![], + span: Span { start: 0, end: 0 }, + }, + ); + let result = eval_block( + &self.engine_state, + &mut stack, + &block, + PipelineData::new(new_span), + ); + + let v: Vec<_> = match result { + Ok(pd) => pd + .into_iter() + .filter_map(move |x| { + let s = x.as_string(); + + match s { + Ok(s) => Some(( + reedline::Span { + start: new_span.start - offset, + end: new_span.end - offset, + }, + s, + )), + Err(_) => None, + } + }) + .filter(|x| x.1.as_bytes().starts_with(&prefix)) + .collect(), + _ => vec![], + }; + + return v; + } + FlatShape::Filepath | FlatShape::GlobPattern => { + let cwd = if let Some(d) = self.engine_state.env_vars.get("PWD") { + match d.as_string() { + Ok(s) => s, + Err(_) => "".to_string(), + } + } else { + "".to_string() + }; + let prefix = String::from_utf8_lossy(&prefix).to_string(); + return file_path_completion(new_span, &prefix, &cwd) + .into_iter() + .map(move |x| { + ( + reedline::Span { + start: x.0.start - offset, + end: x.0.end - offset, + }, + x.1, + ) + }) + .collect(); + } + flat_shape => { + let last = flattened + .iter() + .rev() + .skip_while(|x| x.0.end > pos) + .take_while(|x| { + matches!( + x.1, + FlatShape::InternalCall + | FlatShape::External + | FlatShape::ExternalArg + | FlatShape::Literal + | FlatShape::String + ) + }) + .last(); + + // The last item here would be the earliest shape that could possible by part of this subcommand + let subcommands = if let Some(last) = last { + self.complete_commands( + &working_set, + Span { + start: last.0.start, + end: pos, + }, + offset, + false, + ) + } else { + vec![] + }; + + if !subcommands.is_empty() { + return subcommands; + } + + let commands = + if matches!(flat_shape, nu_parser::FlatShape::External) + || matches!(flat_shape, nu_parser::FlatShape::InternalCall) + || ((new_span.end - new_span.start) == 0) { - match d.as_string() { - Ok(s) => s, - Err(_) => "".to_string(), - } - } else { - "".to_string() - }; - - let preceding_byte = if new_span.start > offset { - working_set - .get_span_contents(Span { - start: new_span.start - 1, - end: new_span.start, - }) - .to_vec() + // we're in a gap or at a command + self.complete_commands(&working_set, new_span, offset, true) } else { vec![] }; - // let prefix = working_set.get_span_contents(flat.0); - let prefix = String::from_utf8_lossy(&prefix).to_string(); - let output = file_path_completion(new_span, &prefix, &cwd) - .into_iter() - .map(move |x| { - if flat_idx == 0 { - // We're in the command position - if x.1.starts_with('"') - && !matches!(preceding_byte.get(0), Some(b'^')) - { - let trimmed = trim_quotes(x.1.as_bytes()); - let trimmed = String::from_utf8_lossy(trimmed) - .to_string(); - let expanded = - nu_path::canonicalize_with(trimmed, &cwd); - if let Ok(expanded) = expanded { - if is_executable::is_executable(expanded) { - (x.0, format!("^{}", x.1)) - } else { - (x.0, x.1) - } + let cwd = if let Some(d) = self.engine_state.env_vars.get("PWD") { + match d.as_string() { + Ok(s) => s, + Err(_) => "".to_string(), + } + } else { + "".to_string() + }; + + let preceding_byte = if new_span.start > offset { + working_set + .get_span_contents(Span { + start: new_span.start - 1, + end: new_span.start, + }) + .to_vec() + } else { + vec![] + }; + // let prefix = working_set.get_span_contents(flat.0); + let prefix = String::from_utf8_lossy(&prefix).to_string(); + let output = file_path_completion(new_span, &prefix, &cwd) + .into_iter() + .map(move |x| { + if flat_idx == 0 { + // We're in the command position + if x.1.starts_with('"') + && !matches!(preceding_byte.get(0), Some(b'^')) + { + let trimmed = trim_quotes(x.1.as_bytes()); + let trimmed = + String::from_utf8_lossy(trimmed).to_string(); + let expanded = + nu_path::canonicalize_with(trimmed, &cwd); + + if let Ok(expanded) = expanded { + if is_executable::is_executable(expanded) { + (x.0, format!("^{}", x.1)) } else { (x.0, x.1) } @@ -405,23 +391,25 @@ impl NuCompleter { } else { (x.0, x.1) } - }) - .map(move |x| { - ( - reedline::Span { - start: x.0.start - offset, - end: x.0.end - offset, - }, - x.1, - ) - }) - .chain(subcommands.into_iter()) - .chain(commands.into_iter()) - .collect::>(); - //output.dedup_by(|a, b| a.1 == b.1); + } else { + (x.0, x.1) + } + }) + .map(move |x| { + ( + reedline::Span { + start: x.0.start - offset, + end: x.0.end - offset, + }, + x.1, + ) + }) + .chain(subcommands.into_iter()) + .chain(commands.into_iter()) + .collect::>(); + //output.dedup_by(|a, b| a.1 == b.1); - return output; - } + return output; } } } diff --git a/crates/nu-engine/src/eval.rs b/crates/nu-engine/src/eval.rs index ff53d1f90f..6890904c23 100644 --- a/crates/nu-engine/src/eval.rs +++ b/crates/nu-engine/src/eval.rs @@ -3,7 +3,7 @@ use std::collections::HashMap; use std::io::Write; use nu_path::expand_path_with; -use nu_protocol::ast::{Block, Call, Expr, Expression, Operator, Statement}; +use nu_protocol::ast::{Block, Call, Expr, Expression, Operator}; use nu_protocol::engine::{EngineState, Stack}; use nu_protocol::{ IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, Range, ShellError, Span, @@ -471,21 +471,19 @@ pub fn eval_block( block: &Block, mut input: PipelineData, ) -> Result { - let num_stmts = block.stmts.len(); - for (stmt_idx, stmt) in block.stmts.iter().enumerate() { - if let Statement::Pipeline(pipeline) = stmt { - for (i, elem) in pipeline.expressions.iter().enumerate() { - input = eval_expression_with_input( - engine_state, - stack, - elem, - input, - i == pipeline.expressions.len() - 1, - )? - } + let num_pipelines = block.len(); + for (pipeline_idx, pipeline) in block.pipelines.iter().enumerate() { + for (i, elem) in pipeline.expressions.iter().enumerate() { + input = eval_expression_with_input( + engine_state, + stack, + elem, + input, + i == pipeline.expressions.len() - 1, + )? } - if stmt_idx < (num_stmts) - 1 { + if pipeline_idx < (num_pipelines) - 1 { match input { PipelineData::Value(Value::Nothing { .. }, ..) => {} _ => { @@ -551,15 +549,13 @@ pub fn eval_block_with_redirect( block: &Block, mut input: PipelineData, ) -> Result { - let num_stmts = block.stmts.len(); - for (stmt_idx, stmt) in block.stmts.iter().enumerate() { - if let Statement::Pipeline(pipeline) = stmt { - for elem in pipeline.expressions.iter() { - input = eval_expression_with_input(engine_state, stack, elem, input, false)? - } + let num_pipelines = block.len(); + for (pipeline_idx, pipeline) in block.pipelines.iter().enumerate() { + for elem in pipeline.expressions.iter() { + input = eval_expression_with_input(engine_state, stack, elem, input, false)? } - if stmt_idx < (num_stmts) - 1 { + if pipeline_idx < (num_pipelines) - 1 { match input { PipelineData::Value(Value::Nothing { .. }, ..) => {} _ => { @@ -625,11 +621,9 @@ pub fn eval_subexpression( block: &Block, mut input: PipelineData, ) -> Result { - for stmt in block.stmts.iter() { - if let Statement::Pipeline(pipeline) = stmt { - for expr in pipeline.expressions.iter() { - input = eval_expression_with_input(engine_state, stack, expr, input, false)? - } + for pipeline in block.pipelines.iter() { + for expr in pipeline.expressions.iter() { + input = eval_expression_with_input(engine_state, stack, expr, input, false)? } } diff --git a/crates/nu-parser/src/errors.rs b/crates/nu-parser/src/errors.rs index 44987e3796..6dcab36cfd 100644 --- a/crates/nu-parser/src/errors.rs +++ b/crates/nu-parser/src/errors.rs @@ -27,10 +27,6 @@ pub enum ParseError { #[diagnostic(code(nu::parser::unclosed_delimiter), url(docsrs))] Unclosed(String, #[label("unclosed {0}")] Span), - #[error("Unknown statement.")] - #[diagnostic(code(nu::parser::unknown_statement), url(docsrs))] - UnknownStatement(#[label("unknown statement")] Span), - #[error("Parse mismatch during operation.")] #[diagnostic(code(nu::parser::parse_mismatch), url(docsrs))] Expected(String, #[label("expected {0}")] Span), @@ -73,7 +69,7 @@ pub enum ParseError { "'{0}' keyword is not allowed in pipeline. Use '{0}' by itself, outside of a pipeline." ) )] - StatementInPipeline(String, #[label("not allowed in pipeline")] Span), + BuiltinCommandInPipeline(String, #[label("not allowed in pipeline")] Span), #[error("Incorrect value")] #[diagnostic(code(nu::parser::incorrect_value), url(docsrs), help("{2}"))] diff --git a/crates/nu-parser/src/flatten.rs b/crates/nu-parser/src/flatten.rs index ea77e89d8c..9f5eeba300 100644 --- a/crates/nu-parser/src/flatten.rs +++ b/crates/nu-parser/src/flatten.rs @@ -1,6 +1,4 @@ -use nu_protocol::ast::{ - Block, Expr, Expression, ImportPatternMember, PathMember, Pipeline, Statement, -}; +use nu_protocol::ast::{Block, Expr, Expression, ImportPatternMember, PathMember, Pipeline}; use nu_protocol::{engine::StateWorkingSet, Span}; use std::fmt::{Display, Formatter, Result}; @@ -63,22 +61,12 @@ impl Display for FlatShape { pub fn flatten_block(working_set: &StateWorkingSet, block: &Block) -> Vec<(Span, FlatShape)> { let mut output = vec![]; - for stmt in &block.stmts { - output.extend(flatten_statement(working_set, stmt)); + for pipeline in &block.pipelines { + output.extend(flatten_pipeline(working_set, pipeline)); } output } -pub fn flatten_statement( - working_set: &StateWorkingSet, - stmt: &Statement, -) -> Vec<(Span, FlatShape)> { - match stmt { - Statement::Pipeline(pipeline) => flatten_pipeline(working_set, pipeline), - _ => vec![], - } -} - pub fn flatten_expression( working_set: &StateWorkingSet, expr: &Expression, diff --git a/crates/nu-parser/src/lib.rs b/crates/nu-parser/src/lib.rs index cb29d8b7df..13d1732c62 100644 --- a/crates/nu-parser/src/lib.rs +++ b/crates/nu-parser/src/lib.rs @@ -8,9 +8,7 @@ mod parser; mod type_check; pub use errors::ParseError; -pub use flatten::{ - flatten_block, flatten_expression, flatten_pipeline, flatten_statement, FlatShape, -}; +pub use flatten::{flatten_block, flatten_expression, flatten_pipeline, FlatShape}; pub use known_external::KnownExternal; pub use lex::{lex, Token, TokenContents}; pub use lite_parse::{lite_parse, LiteBlock}; diff --git a/crates/nu-parser/src/lite_parse.rs b/crates/nu-parser/src/lite_parse.rs index 922ddd84de..05d1800e6b 100644 --- a/crates/nu-parser/src/lite_parse.rs +++ b/crates/nu-parser/src/lite_parse.rs @@ -31,17 +31,17 @@ impl LiteCommand { } #[derive(Debug)] -pub struct LiteStatement { +pub struct LitePipeline { pub commands: Vec, } -impl Default for LiteStatement { +impl Default for LitePipeline { fn default() -> Self { Self::new() } } -impl LiteStatement { +impl LitePipeline { pub fn new() -> Self { Self { commands: vec![] } } @@ -57,7 +57,7 @@ impl LiteStatement { #[derive(Debug)] pub struct LiteBlock { - pub block: Vec, + pub block: Vec, } impl Default for LiteBlock { @@ -71,7 +71,7 @@ impl LiteBlock { Self { block: vec![] } } - pub fn push(&mut self, pipeline: LiteStatement) { + pub fn push(&mut self, pipeline: LitePipeline) { self.block.push(pipeline); } @@ -82,7 +82,7 @@ impl LiteBlock { pub fn lite_parse(tokens: &[Token]) -> (LiteBlock, Option) { let mut block = LiteBlock::new(); - let mut curr_pipeline = LiteStatement::new(); + let mut curr_pipeline = LitePipeline::new(); let mut curr_command = LiteCommand::new(); let mut last_token = TokenContents::Eol; @@ -117,7 +117,7 @@ pub fn lite_parse(tokens: &[Token]) -> (LiteBlock, Option) { if !curr_pipeline.is_empty() { block.push(curr_pipeline); - curr_pipeline = LiteStatement::new(); + curr_pipeline = LitePipeline::new(); } } @@ -138,7 +138,7 @@ pub fn lite_parse(tokens: &[Token]) -> (LiteBlock, Option) { if !curr_pipeline.is_empty() { block.push(curr_pipeline); - curr_pipeline = LiteStatement::new(); + curr_pipeline = LitePipeline::new(); } last_token = TokenContents::Semicolon; diff --git a/crates/nu-parser/src/parse_keywords.rs b/crates/nu-parser/src/parse_keywords.rs index 69d2cefa96..c40a618c32 100644 --- a/crates/nu-parser/src/parse_keywords.rs +++ b/crates/nu-parser/src/parse_keywords.rs @@ -2,7 +2,7 @@ use nu_path::canonicalize_with; use nu_protocol::{ ast::{ Block, Call, Expr, Expression, ImportPattern, ImportPatternHead, ImportPatternMember, - Pipeline, Statement, + Pipeline, }, engine::StateWorkingSet, span, Exportable, Overlay, PositionalArg, Span, SyntaxShape, Type, CONFIG_VARIABLE_ID, @@ -14,7 +14,7 @@ use crate::{ lex, lite_parse, lite_parse::LiteCommand, parser::{ - check_call, check_name, garbage, garbage_statement, parse, parse_block_expression, + check_call, check_name, garbage, garbage_pipeline, parse, parse_block_expression, parse_internal_call, parse_multispan_value, parse_signature, parse_string, parse_var_with_opt_type, trim_quotes, }, @@ -245,7 +245,7 @@ fn build_usage(working_set: &StateWorkingSet, spans: &[Span]) -> String { pub fn parse_def( working_set: &mut StateWorkingSet, lite_command: &LiteCommand, -) -> (Statement, Option) { +) -> (Pipeline, Option) { let spans = &lite_command.parts[..]; let usage = build_usage(working_set, &lite_command.comments); @@ -256,7 +256,7 @@ pub fn parse_def( let def_call = working_set.get_span_contents(spans[0]).to_vec(); if def_call != b"def" && def_call != b"def-env" { return ( - garbage_statement(spans), + garbage_pipeline(spans), Some(ParseError::UnknownState( "internal error: Wrong call name for def function".into(), span(spans), @@ -270,7 +270,7 @@ pub fn parse_def( let (call, call_span) = match working_set.find_decl(&def_call) { None => { return ( - garbage_statement(spans), + garbage_pipeline(spans), Some(ParseError::UnknownState( "internal error: def declaration not found".into(), span(spans), @@ -308,12 +308,12 @@ pub fn parse_def( err = check_call(call_span, &sig, &call).or(err); if err.is_some() || call.has_flag("help") { return ( - Statement::Pipeline(Pipeline::from_vec(vec![Expression { + Pipeline::from_vec(vec![Expression { expr: Expr::Call(call), span: call_span, ty: Type::Unknown, custom_completion: None, - }])), + }]), err, ); } @@ -365,12 +365,12 @@ pub fn parse_def( } ( - Statement::Pipeline(Pipeline::from_vec(vec![Expression { + Pipeline::from_vec(vec![Expression { expr: Expr::Call(call), span: call_span, ty: Type::Unknown, custom_completion: None, - }])), + }]), error, ) } @@ -378,7 +378,7 @@ pub fn parse_def( pub fn parse_extern( working_set: &mut StateWorkingSet, lite_command: &LiteCommand, -) -> (Statement, Option) { +) -> (Pipeline, Option) { let spans = &lite_command.parts[..]; let mut error = None; @@ -390,7 +390,7 @@ pub fn parse_extern( let extern_call = working_set.get_span_contents(spans[0]).to_vec(); if extern_call != b"extern" { return ( - garbage_statement(spans), + garbage_pipeline(spans), Some(ParseError::UnknownState( "internal error: Wrong call name for extern function".into(), span(spans), @@ -404,7 +404,7 @@ pub fn parse_extern( let (call, call_span) = match working_set.find_decl(&extern_call) { None => { return ( - garbage_statement(spans), + garbage_pipeline(spans), Some(ParseError::UnknownState( "internal error: def declaration not found".into(), span(spans), @@ -466,12 +466,12 @@ pub fn parse_extern( } ( - Statement::Pipeline(Pipeline::from_vec(vec![Expression { + Pipeline::from_vec(vec![Expression { expr: Expr::Call(call), span: call_span, ty: Type::Unknown, custom_completion: None, - }])), + }]), error, ) } @@ -479,15 +479,12 @@ pub fn parse_extern( pub fn parse_alias( working_set: &mut StateWorkingSet, spans: &[Span], -) -> (Statement, Option) { +) -> (Pipeline, Option) { let name = working_set.get_span_contents(spans[0]); if name == b"alias" { if let Some((span, err)) = check_name(working_set, spans) { - return ( - Statement::Pipeline(Pipeline::from_vec(vec![garbage(*span)])), - Some(err), - ); + return (Pipeline::from_vec(vec![garbage(*span)]), Some(err)); } if let Some(decl_id) = working_set.find_decl(b"alias") { @@ -512,19 +509,19 @@ pub fn parse_alias( } return ( - Statement::Pipeline(Pipeline::from_vec(vec![Expression { + Pipeline::from_vec(vec![Expression { expr: Expr::Call(call), span: span(spans), ty: Type::Unknown, custom_completion: None, - }])), + }]), None, ); } } ( - garbage_statement(spans), + garbage_pipeline(spans), Some(ParseError::InternalError( "Alias statement unparseable".into(), span(spans), @@ -535,14 +532,14 @@ pub fn parse_alias( pub fn parse_export( working_set: &mut StateWorkingSet, lite_command: &LiteCommand, -) -> (Statement, Option, Option) { +) -> (Pipeline, Option, Option) { let spans = &lite_command.parts[..]; let mut error = None; let export_span = if let Some(sp) = spans.get(0) { if working_set.get_span_contents(*sp) != b"export" { return ( - garbage_statement(spans), + garbage_pipeline(spans), None, Some(ParseError::UnknownState( "expected export statement".into(), @@ -554,7 +551,7 @@ pub fn parse_export( *sp } else { return ( - garbage_statement(spans), + garbage_pipeline(spans), None, Some(ParseError::UnknownState( "got empty input for parsing export statement".into(), @@ -567,7 +564,7 @@ pub fn parse_export( id } else { return ( - garbage_statement(spans), + garbage_pipeline(spans), None, Some(ParseError::InternalError( "missing export command".into(), @@ -591,14 +588,14 @@ pub fn parse_export( comments: lite_command.comments.clone(), parts: spans[1..].to_vec(), }; - let (stmt, err) = parse_def(working_set, &lite_command); + let (pipeline, err) = parse_def(working_set, &lite_command); error = error.or(err); let export_def_decl_id = if let Some(id) = working_set.find_decl(b"export def") { id } else { return ( - garbage_statement(spans), + garbage_pipeline(spans), None, Some(ParseError::InternalError( "missing 'export def' command".into(), @@ -608,24 +605,15 @@ pub fn parse_export( }; // Trying to warp the 'def' call into the 'export def' in a very clumsy way - if let Statement::Pipeline(ref pipe) = stmt { - if let Some(Expression { - expr: Expr::Call(ref def_call), - .. - }) = pipe.expressions.get(0) - { - call = def_call.clone(); + if let Some(Expression { + expr: Expr::Call(ref def_call), + .. + }) = pipeline.expressions.get(0) + { + call = def_call.clone(); - call.head = span(&spans[0..=1]); - call.decl_id = export_def_decl_id; - } else { - error = error.or_else(|| { - Some(ParseError::InternalError( - "unexpected output from parsing a definition".into(), - span(&spans[1..]), - )) - }); - } + call.head = span(&spans[0..=1]); + call.decl_id = export_def_decl_id; } else { error = error.or_else(|| { Some(ParseError::InternalError( @@ -658,7 +646,7 @@ pub fn parse_export( comments: lite_command.comments.clone(), parts: spans[1..].to_vec(), }; - let (stmt, err) = parse_def(working_set, &lite_command); + let (pipeline, err) = parse_def(working_set, &lite_command); error = error.or(err); let export_def_decl_id = if let Some(id) = working_set.find_decl(b"export def-env") @@ -666,7 +654,7 @@ pub fn parse_export( id } else { return ( - garbage_statement(spans), + garbage_pipeline(spans), None, Some(ParseError::InternalError( "missing 'export def-env' command".into(), @@ -676,24 +664,15 @@ pub fn parse_export( }; // Trying to warp the 'def' call into the 'export def' in a very clumsy way - if let Statement::Pipeline(ref pipe) = stmt { - if let Some(Expression { - expr: Expr::Call(ref def_call), - .. - }) = pipe.expressions.get(0) - { - call = def_call.clone(); + if let Some(Expression { + expr: Expr::Call(ref def_call), + .. + }) = pipeline.expressions.get(0) + { + call = def_call.clone(); - call.head = span(&spans[0..=1]); - call.decl_id = export_def_decl_id; - } else { - error = error.or_else(|| { - Some(ParseError::InternalError( - "unexpected output from parsing a definition".into(), - span(&spans[1..]), - )) - }); - } + call.head = span(&spans[0..=1]); + call.decl_id = export_def_decl_id; } else { error = error.or_else(|| { Some(ParseError::InternalError( @@ -726,7 +705,7 @@ pub fn parse_export( call.decl_id = id; } else { return ( - garbage_statement(spans), + garbage_pipeline(spans), None, Some(ParseError::InternalError( "missing 'export env' command".into(), @@ -833,12 +812,12 @@ pub fn parse_export( }; ( - Statement::Pipeline(Pipeline::from_vec(vec![Expression { + Pipeline::from_vec(vec![Expression { expr: Expr::Call(call), span: span(spans), ty: Type::Unknown, custom_completion: None, - }])), + }]), exportable, error, ) @@ -876,16 +855,16 @@ pub fn parse_module_block( if pipeline.commands.len() == 1 { let name = working_set.get_span_contents(pipeline.commands[0].parts[0]); - let (stmt, err) = match name { + let (pipeline, err) = match name { b"def" | b"def-env" => { - let (stmt, err) = parse_def(working_set, &pipeline.commands[0]); + let (pipeline, err) = parse_def(working_set, &pipeline.commands[0]); - (stmt, err) + (pipeline, err) } b"extern" => { - let (stmt, err) = parse_extern(working_set, &pipeline.commands[0]); + let (pipeline, err) = parse_extern(working_set, &pipeline.commands[0]); - (stmt, err) + (pipeline, err) } // TODO: Currently, it is not possible to define a private env var. // TODO: Exported env vars are usable iside the module only if correctly @@ -896,7 +875,7 @@ pub fn parse_module_block( // will work only if you call `use foo *; b` but not with `use foo; foo b` // since in the second case, the name of the env var would be $env."foo a". b"export" => { - let (stmt, exportable, err) = + let (pipe, exportable, err) = parse_export(working_set, &pipeline.commands[0]); if err.is_none() { @@ -915,10 +894,10 @@ pub fn parse_module_block( } } - (stmt, err) + (pipe, err) } _ => ( - garbage_statement(&pipeline.commands[0].parts), + garbage_pipeline(&pipeline.commands[0].parts), Some(ParseError::UnexpectedKeyword( "expected def or export keyword".into(), pipeline.commands[0].parts[0], @@ -930,10 +909,10 @@ pub fn parse_module_block( error = err; } - stmt + pipeline } else { error = Some(ParseError::Expected("not a pipeline".into(), span)); - garbage_statement(&[span]) + garbage_pipeline(&[span]) } }) .into(); @@ -946,7 +925,7 @@ pub fn parse_module_block( pub fn parse_module( working_set: &mut StateWorkingSet, spans: &[Span], -) -> (Statement, Option) { +) -> (Pipeline, Option) { // TODO: Currently, module is closing over its parent scope (i.e., defs in the parent scope are // visible and usable in this module's scope). We want to disable that for files. @@ -970,7 +949,7 @@ pub fn parse_module( start += 1; } else { return ( - garbage_statement(spans), + garbage_pipeline(spans), Some(ParseError::Expected("block".into(), block_span)), ); } @@ -1009,17 +988,17 @@ pub fn parse_module( }); ( - Statement::Pipeline(Pipeline::from_vec(vec![Expression { + Pipeline::from_vec(vec![Expression { expr: Expr::Call(call), span: span(spans), ty: Type::Unknown, custom_completion: None, - }])), + }]), error, ) } else { ( - garbage_statement(spans), + garbage_pipeline(spans), Some(ParseError::UnknownState( "Expected structure: module {}".into(), span(spans), @@ -1031,10 +1010,10 @@ pub fn parse_module( pub fn parse_use( working_set: &mut StateWorkingSet, spans: &[Span], -) -> (Statement, Option) { +) -> (Pipeline, Option) { if working_set.get_span_contents(spans[0]) != b"use" { return ( - garbage_statement(spans), + garbage_pipeline(spans), Some(ParseError::UnknownState( "internal error: Wrong call name for 'use' command".into(), span(spans), @@ -1052,12 +1031,12 @@ pub fn parse_use( err = check_call(call_span, &decl.signature(), &call).or(err); if err.is_some() || call.has_flag("help") { return ( - Statement::Pipeline(Pipeline::from_vec(vec![Expression { + Pipeline::from_vec(vec![Expression { expr: Expr::Call(call), span: call_span, ty: Type::Unknown, custom_completion: None, - }])), + }]), err, ); } @@ -1066,7 +1045,7 @@ pub fn parse_use( } None => { return ( - garbage_statement(spans), + garbage_pipeline(spans), Some(ParseError::UnknownState( "internal error: 'use' declaration not found".into(), span(spans), @@ -1080,7 +1059,7 @@ pub fn parse_use( pattern } else { return ( - garbage_statement(spans), + garbage_pipeline(spans), Some(ParseError::UnknownState( "internal error: Import pattern positional is not import pattern".into(), call_span, @@ -1089,7 +1068,7 @@ pub fn parse_use( } } else { return ( - garbage_statement(spans), + garbage_pipeline(spans), Some(ParseError::UnknownState( "internal error: Missing required positional after call parsing".into(), call_span, @@ -1117,12 +1096,12 @@ pub fn parse_use( stem.to_string_lossy().to_string() } else { return ( - Statement::Pipeline(Pipeline::from_vec(vec![Expression { + Pipeline::from_vec(vec![Expression { expr: Expr::Call(call), span: call_span, ty: Type::Unknown, custom_completion: None, - }])), + }]), Some(ParseError::ModuleNotFound(spans[1])), ); }; @@ -1152,12 +1131,12 @@ pub fn parse_use( ) } else { return ( - Statement::Pipeline(Pipeline::from_vec(vec![Expression { + Pipeline::from_vec(vec![Expression { expr: Expr::Call(call), span: call_span, ty: Type::Unknown, custom_completion: None, - }])), + }]), Some(ParseError::ModuleNotFound(spans[1])), ); } @@ -1169,10 +1148,7 @@ pub fn parse_use( (ImportPattern::new(), Overlay::new()) } } else { - return ( - garbage_statement(spans), - Some(ParseError::NonUtf8(spans[1])), - ); + return (garbage_pipeline(spans), Some(ParseError::NonUtf8(spans[1]))); } }; @@ -1228,12 +1204,12 @@ pub fn parse_use( }); ( - Statement::Pipeline(Pipeline::from_vec(vec![Expression { + Pipeline::from_vec(vec![Expression { expr: Expr::Call(call), span: span(spans), ty: Type::Unknown, custom_completion: None, - }])), + }]), error, ) } @@ -1241,10 +1217,10 @@ pub fn parse_use( pub fn parse_hide( working_set: &mut StateWorkingSet, spans: &[Span], -) -> (Statement, Option) { +) -> (Pipeline, Option) { if working_set.get_span_contents(spans[0]) != b"hide" { return ( - garbage_statement(spans), + garbage_pipeline(spans), Some(ParseError::UnknownState( "internal error: Wrong call name for 'hide' command".into(), span(spans), @@ -1262,12 +1238,12 @@ pub fn parse_hide( err = check_call(call_span, &decl.signature(), &call).or(err); if err.is_some() || call.has_flag("help") { return ( - Statement::Pipeline(Pipeline::from_vec(vec![Expression { + Pipeline::from_vec(vec![Expression { expr: Expr::Call(call), span: call_span, ty: Type::Unknown, custom_completion: None, - }])), + }]), err, ); } @@ -1276,7 +1252,7 @@ pub fn parse_hide( } None => { return ( - garbage_statement(spans), + garbage_pipeline(spans), Some(ParseError::UnknownState( "internal error: 'hide' declaration not found".into(), span(spans), @@ -1290,7 +1266,7 @@ pub fn parse_hide( pattern } else { return ( - garbage_statement(spans), + garbage_pipeline(spans), Some(ParseError::UnknownState( "internal error: Import pattern positional is not import pattern".into(), call_span, @@ -1299,7 +1275,7 @@ pub fn parse_hide( } } else { return ( - garbage_statement(spans), + garbage_pipeline(spans), Some(ParseError::UnknownState( "internal error: Missing required positional after call parsing".into(), call_span, @@ -1339,7 +1315,7 @@ pub fn parse_hide( } } else { return ( - garbage_statement(spans), + garbage_pipeline(spans), Some(ParseError::ModuleNotFound(spans[1])), ); }; @@ -1427,17 +1403,17 @@ pub fn parse_hide( }); ( - Statement::Pipeline(Pipeline::from_vec(vec![Expression { + Pipeline::from_vec(vec![Expression { expr: Expr::Call(call), span: span(spans), ty: Type::Unknown, custom_completion: None, - }])), + }]), error, ) } else { ( - garbage_statement(spans), + garbage_pipeline(spans), Some(ParseError::UnknownState( "Expected structure: hide ".into(), span(spans), @@ -1449,15 +1425,12 @@ pub fn parse_hide( pub fn parse_let( working_set: &mut StateWorkingSet, spans: &[Span], -) -> (Statement, Option) { +) -> (Pipeline, Option) { let name = working_set.get_span_contents(spans[0]); if name == b"let" { if let Some((span, err)) = check_name(working_set, spans) { - return ( - Statement::Pipeline(Pipeline::from_vec(vec![garbage(*span)])), - Some(err), - ); + return (Pipeline::from_vec(vec![garbage(*span)]), Some(err)); } if let Some(decl_id) = working_set.find_decl(b"let") { @@ -1511,12 +1484,12 @@ pub fn parse_let( }); return ( - Statement::Pipeline(Pipeline::from_vec(vec![Expression { + Pipeline::from_vec(vec![Expression { expr: Expr::Call(call), span: nu_protocol::span(spans), ty: Type::Unknown, custom_completion: None, - }])), + }]), error, ); } @@ -1525,20 +1498,20 @@ pub fn parse_let( let (call, err) = parse_internal_call(working_set, spans[0], &spans[1..], decl_id); return ( - Statement::Pipeline(Pipeline { + Pipeline { expressions: vec![Expression { expr: Expr::Call(call), span: nu_protocol::span(spans), ty: Type::Unknown, custom_completion: None, }], - }), + }, err, ); } } ( - garbage_statement(spans), + garbage_pipeline(spans), Some(ParseError::UnknownState( "internal error: let statement unparseable".into(), span(spans), @@ -1549,7 +1522,7 @@ pub fn parse_let( pub fn parse_source( working_set: &mut StateWorkingSet, spans: &[Span], -) -> (Statement, Option) { +) -> (Pipeline, Option) { let mut error = None; let name = working_set.get_span_contents(spans[0]); @@ -1580,12 +1553,12 @@ pub fn parse_source( if err.is_some() { // Unsuccessful parse of file return ( - Statement::Pipeline(Pipeline::from_vec(vec![Expression { + Pipeline::from_vec(vec![Expression { expr: Expr::Call(call), span: span(&spans[1..]), ty: Type::Unknown, custom_completion: None, - }])), + }]), // Return the file parse error err, ); @@ -1605,12 +1578,12 @@ pub fn parse_source( }); return ( - Statement::Pipeline(Pipeline::from_vec(vec![Expression { + Pipeline::from_vec(vec![Expression { expr: Expr::Call(call_with_block), span: span(spans), ty: Type::Unknown, custom_completion: None, - }])), + }]), None, ); } @@ -1619,25 +1592,22 @@ pub fn parse_source( error = error.or(Some(ParseError::FileNotFound(filename, spans[1]))); } } else { - return ( - garbage_statement(spans), - Some(ParseError::NonUtf8(spans[1])), - ); + return (garbage_pipeline(spans), Some(ParseError::NonUtf8(spans[1]))); } } return ( - Statement::Pipeline(Pipeline::from_vec(vec![Expression { + Pipeline::from_vec(vec![Expression { expr: Expr::Call(call), span: span(spans), ty: Type::Unknown, custom_completion: None, - }])), + }]), error, ); } } ( - garbage_statement(spans), + garbage_pipeline(spans), Some(ParseError::UnknownState( "internal error: source statement unparseable".into(), span(spans), @@ -1649,7 +1619,7 @@ pub fn parse_source( pub fn parse_register( working_set: &mut StateWorkingSet, spans: &[Span], -) -> (Statement, Option) { +) -> (Pipeline, Option) { use nu_plugin::{get_signature, EncodingType, PluginDeclaration}; use nu_protocol::Signature; let cwd = working_set.get_cwd(); @@ -1658,7 +1628,7 @@ pub fn parse_register( // Maybe this is not necessary but it is a sanity check if working_set.get_span_contents(spans[0]) != b"register" { return ( - garbage_statement(spans), + garbage_pipeline(spans), Some(ParseError::UnknownState( "internal error: Wrong call name for parse plugin function".into(), span(spans), @@ -1672,7 +1642,7 @@ pub fn parse_register( let (call, call_span) = match working_set.find_decl(b"register") { None => { return ( - garbage_statement(spans), + garbage_pipeline(spans), Some(ParseError::UnknownState( "internal error: Register declaration not found".into(), span(spans), @@ -1688,12 +1658,12 @@ pub fn parse_register( err = check_call(call_span, &decl.signature(), &call).or(err); if err.is_some() || call.has_flag("help") { return ( - Statement::Pipeline(Pipeline::from_vec(vec![Expression { + Pipeline::from_vec(vec![Expression { expr: Expr::Call(call), span: call_span, ty: Type::Unknown, custom_completion: None, - }])), + }]), err, ); } @@ -1779,12 +1749,12 @@ pub fn parse_register( Ok(path) => Some(path), Err(err) => { return ( - Statement::Pipeline(Pipeline::from_vec(vec![Expression { + Pipeline::from_vec(vec![Expression { expr: Expr::Call(call), span: call_span, ty: Type::Unknown, custom_completion: None, - }])), + }]), Some(err), ); } @@ -1829,12 +1799,12 @@ pub fn parse_register( .err(); ( - Statement::Pipeline(Pipeline::from_vec(vec![Expression { + Pipeline::from_vec(vec![Expression { expr: Expr::Call(call), span: call_span, ty: Type::Nothing, custom_completion: None, - }])), + }]), error, ) } diff --git a/crates/nu-parser/src/parser.rs b/crates/nu-parser/src/parser.rs index 442adb69ee..eacc980905 100644 --- a/crates/nu-parser/src/parser.rs +++ b/crates/nu-parser/src/parser.rs @@ -10,7 +10,6 @@ use nu_protocol::{ ast::{ Block, Call, CellPath, Expr, Expression, FullCellPath, ImportPattern, ImportPatternHead, ImportPatternMember, Operator, PathMember, Pipeline, RangeInclusion, RangeOperator, - Statement, }, engine::StateWorkingSet, span, BlockId, Flag, PositionalArg, Signature, Span, Spanned, SyntaxShape, Type, Unit, VarId, @@ -34,8 +33,8 @@ pub fn garbage(span: Span) -> Expression { Expression::garbage(span) } -pub fn garbage_statement(spans: &[Span]) -> Statement { - Statement::Pipeline(Pipeline::from_vec(vec![garbage(span(spans))])) +pub fn garbage_pipeline(spans: &[Span]) -> Pipeline { + Pipeline::from_vec(vec![garbage(span(spans))]) } fn is_identifier_byte(b: u8) -> bool { @@ -2293,7 +2292,7 @@ pub fn parse_row_condition( let mut pipeline = Pipeline::new(); pipeline.expressions.push(expression); - block.stmts.push(Statement::Pipeline(pipeline)); + block.pipelines.push(pipeline); block.signature.required_positional.push(PositionalArg { name: "$it".into(), @@ -3413,31 +3412,43 @@ pub fn parse_expression( match bytes { b"def" => ( parse_call(working_set, &spans[pos..], expand_aliases, spans[0]).0, - Some(ParseError::StatementInPipeline("def".into(), spans[0])), + Some(ParseError::BuiltinCommandInPipeline("def".into(), spans[0])), ), b"extern" => ( parse_call(working_set, &spans[pos..], expand_aliases, spans[0]).0, - Some(ParseError::StatementInPipeline("extern".into(), spans[0])), + Some(ParseError::BuiltinCommandInPipeline( + "extern".into(), + spans[0], + )), ), b"let" => ( parse_call(working_set, &spans[pos..], expand_aliases, spans[0]).0, - Some(ParseError::StatementInPipeline("let".into(), spans[0])), + Some(ParseError::BuiltinCommandInPipeline("let".into(), spans[0])), ), b"alias" => ( parse_call(working_set, &spans[pos..], expand_aliases, spans[0]).0, - Some(ParseError::StatementInPipeline("alias".into(), spans[0])), + Some(ParseError::BuiltinCommandInPipeline( + "alias".into(), + spans[0], + )), ), b"module" => ( parse_call(working_set, &spans[pos..], expand_aliases, spans[0]).0, - Some(ParseError::StatementInPipeline("module".into(), spans[0])), + Some(ParseError::BuiltinCommandInPipeline( + "module".into(), + spans[0], + )), ), b"use" => ( parse_call(working_set, &spans[pos..], expand_aliases, spans[0]).0, - Some(ParseError::StatementInPipeline("use".into(), spans[0])), + Some(ParseError::BuiltinCommandInPipeline("use".into(), spans[0])), ), b"source" => ( parse_call(working_set, &spans[pos..], expand_aliases, spans[0]).0, - Some(ParseError::StatementInPipeline("source".into(), spans[0])), + Some(ParseError::BuiltinCommandInPipeline( + "source".into(), + spans[0], + )), ), b"export" => ( parse_call(working_set, &spans[pos..], expand_aliases, spans[0]).0, @@ -3445,12 +3456,18 @@ pub fn parse_expression( ), b"hide" => ( parse_call(working_set, &spans[pos..], expand_aliases, spans[0]).0, - Some(ParseError::StatementInPipeline("hide".into(), spans[0])), + Some(ParseError::BuiltinCommandInPipeline( + "hide".into(), + spans[0], + )), ), #[cfg(feature = "plugin")] b"register" => ( parse_call(working_set, &spans[pos..], expand_aliases, spans[0]).0, - Some(ParseError::StatementInPipeline("plugin".into(), spans[0])), + Some(ParseError::BuiltinCommandInPipeline( + "plugin".into(), + spans[0], + )), ), b"for" => parse_for(working_set, spans), @@ -3464,9 +3481,9 @@ pub fn parse_expression( if let Some(decl_id) = with_env { let mut block = Block::default(); let ty = output.ty.clone(); - block.stmts = vec![Statement::Pipeline(Pipeline { + block.pipelines = vec![Pipeline { expressions: vec![output], - })]; + }]; let block_id = working_set.add_block(block); @@ -3530,10 +3547,10 @@ pub fn parse_variable( } } -pub fn parse_statement( +pub fn parse_builtin_commands( working_set: &mut StateWorkingSet, lite_command: &LiteCommand, -) -> (Statement, Option) { +) -> (Pipeline, Option) { let name = working_set.get_span_contents(lite_command.parts[0]); match name { @@ -3542,14 +3559,14 @@ pub fn parse_statement( b"let" => parse_let(working_set, &lite_command.parts), b"for" => { let (expr, err) = parse_for(working_set, &lite_command.parts); - (Statement::Pipeline(Pipeline::from_vec(vec![expr])), err) + (Pipeline::from_vec(vec![expr]), err) } b"alias" => parse_alias(working_set, &lite_command.parts), b"module" => parse_module(working_set, &lite_command.parts), b"use" => parse_use(working_set, &lite_command.parts), b"source" => parse_source(working_set, &lite_command.parts), b"export" => ( - garbage_statement(&lite_command.parts), + garbage_pipeline(&lite_command.parts), Some(ParseError::UnexpectedKeyword( "export".into(), lite_command.parts[0], @@ -3560,7 +3577,7 @@ pub fn parse_statement( b"register" => parse_register(working_set, &lite_command.parts), _ => { let (expr, err) = parse_expression(working_set, &lite_command.parts, true); - (Statement::Pipeline(Pipeline::from_vec(vec![expr])), err) + (Pipeline::from_vec(vec![expr]), err) } } } @@ -3691,40 +3708,39 @@ pub fn parse_block( } } - Statement::Pipeline(Pipeline { + Pipeline { expressions: output, - }) + } } else { - let (mut stmt, err) = parse_statement(working_set, &pipeline.commands[0]); + let (mut pipeline, err) = + parse_builtin_commands(working_set, &pipeline.commands[0]); if idx == 0 { if let Some(let_decl_id) = working_set.find_decl(b"let") { if let Some(let_env_decl_id) = working_set.find_decl(b"let-env") { - if let Statement::Pipeline(pipeline) = &mut stmt { - for expr in pipeline.expressions.iter_mut() { - if let Expression { - expr: Expr::Call(call), - .. - } = expr + for expr in pipeline.expressions.iter_mut() { + if let Expression { + expr: Expr::Call(call), + .. + } = expr + { + if call.decl_id == let_decl_id + || call.decl_id == let_env_decl_id { - if call.decl_id == let_decl_id - || call.decl_id == let_env_decl_id + // Do an expansion + if let Some(Expression { + expr: Expr::Keyword(_, _, expr), + .. + }) = call.positional.get_mut(1) { - // Do an expansion - if let Some(Expression { - expr: Expr::Keyword(_, _, expr), - .. - }) = call.positional.get_mut(1) - { - if expr.has_in_variable(working_set) { - *expr = Box::new(wrap_expr_with_collect( - working_set, - expr, - )); - } + if expr.has_in_variable(working_set) { + *expr = Box::new(wrap_expr_with_collect( + working_set, + expr, + )); } - continue; } + continue; } } } @@ -3736,7 +3752,7 @@ pub fn parse_block( error = err; } - stmt + pipeline } }) .into(); @@ -3778,15 +3794,9 @@ pub fn discover_captures_in_block( } } - for stmt in &block.stmts { - match stmt { - Statement::Pipeline(pipeline) => { - let result = - discover_captures_in_pipeline(working_set, pipeline, seen, seen_blocks); - output.extend(&result); - } - Statement::Declaration(_) => {} - } + for pipeline in &block.pipelines { + let result = discover_captures_in_pipeline(working_set, pipeline, seen, seen_blocks); + output.extend(&result); } output @@ -4028,9 +4038,9 @@ fn wrap_expr_with_collect(working_set: &mut StateWorkingSet, expr: &Expression) expr.replace_in_variable(working_set, var_id); let block = Block { - stmts: vec![Statement::Pipeline(Pipeline { + pipelines: vec![Pipeline { expressions: vec![expr], - })], + }], signature: Box::new(signature), ..Default::default() }; diff --git a/crates/nu-parser/tests/test_lite_parser.rs b/crates/nu-parser/tests/test_lite_parser.rs index f9c638e892..b92db98c46 100644 --- a/crates/nu-parser/tests/test_lite_parser.rs +++ b/crates/nu-parser/tests/test_lite_parser.rs @@ -109,7 +109,7 @@ fn separated_comments_dont_stack() -> Result<(), ParseError> { } #[test] -fn multiple_statements() -> Result<(), ParseError> { +fn multiple_pipelines() -> Result<(), ParseError> { // Code: // # A comment // let a = ( 3 + ( diff --git a/crates/nu-parser/tests/test_parser.rs b/crates/nu-parser/tests/test_parser.rs index 6c70c474b7..6960d8a077 100644 --- a/crates/nu-parser/tests/test_parser.rs +++ b/crates/nu-parser/tests/test_parser.rs @@ -1,7 +1,7 @@ use nu_parser::ParseError; use nu_parser::*; use nu_protocol::{ - ast::{Expr, Expression, Pipeline, Statement}, + ast::{Expr, Expression}, engine::{Command, EngineState, Stack, StateWorkingSet}, Signature, SyntaxShape, }; @@ -50,19 +50,15 @@ pub fn parse_int() { assert!(err.is_none()); assert!(block.len() == 1); - match &block[0] { - Statement::Pipeline(Pipeline { expressions }) => { - assert!(expressions.len() == 1); - assert!(matches!( - expressions[0], - Expression { - expr: Expr::Int(3), - .. - } - )) + let expressions = &block[0]; + assert!(expressions.len() == 1); + assert!(matches!( + expressions[0], + Expression { + expr: Expr::Int(3), + .. } - _ => panic!("No match"), - } + )) } #[test] @@ -78,19 +74,15 @@ pub fn parse_call() { assert!(err.is_none()); assert!(block.len() == 1); - match &block[0] { - Statement::Pipeline(Pipeline { expressions }) => { - assert_eq!(expressions.len(), 1); + let expressions = &block[0]; + assert_eq!(expressions.len(), 1); - if let Expression { - expr: Expr::Call(call), - .. - } = &expressions[0] - { - assert_eq!(call.decl_id, 0); - } - } - _ => panic!("not a call"), + if let Expression { + expr: Expr::Call(call), + .. + } = &expressions[0] + { + assert_eq!(call.decl_id, 0); } } @@ -186,19 +178,16 @@ fn test_nothing_comparisson_eq() { assert!(err.is_none()); assert!(block.len() == 1); - match &block[0] { - Statement::Pipeline(Pipeline { expressions }) => { - assert!(expressions.len() == 1); - assert!(matches!( - &expressions[0], - Expression { - expr: Expr::BinaryOp(..), - .. - } - )) + + let expressions = &block[0]; + assert!(expressions.len() == 1); + assert!(matches!( + &expressions[0], + Expression { + expr: Expr::BinaryOp(..), + .. } - _ => panic!("No match"), - } + )) } #[test] @@ -209,19 +198,16 @@ fn test_nothing_comparisson_neq() { assert!(err.is_none()); assert!(block.len() == 1); - match &block[0] { - Statement::Pipeline(Pipeline { expressions }) => { - assert!(expressions.len() == 1); - assert!(matches!( - &expressions[0], - Expression { - expr: Expr::BinaryOp(..), - .. - } - )) + + let expressions = &block[0]; + assert!(expressions.len() == 1); + assert!(matches!( + &expressions[0], + Expression { + expr: Expr::BinaryOp(..), + .. } - _ => panic!("No match"), - } + )) } mod range { @@ -237,27 +223,24 @@ mod range { assert!(err.is_none()); assert!(block.len() == 1); - match &block[0] { - Statement::Pipeline(Pipeline { expressions }) => { - assert!(expressions.len() == 1); - assert!(matches!( - expressions[0], - Expression { - expr: Expr::Range( - Some(_), - None, - Some(_), - RangeOperator { - inclusion: RangeInclusion::Inclusive, - .. - } - ), + + let expressions = &block[0]; + assert!(expressions.len() == 1); + assert!(matches!( + expressions[0], + Expression { + expr: Expr::Range( + Some(_), + None, + Some(_), + RangeOperator { + inclusion: RangeInclusion::Inclusive, .. } - )) + ), + .. } - _ => panic!("No match"), - } + )) } #[test] @@ -269,27 +252,24 @@ mod range { assert!(err.is_none()); assert!(block.len() == 1); - match &block[0] { - Statement::Pipeline(Pipeline { expressions }) => { - assert!(expressions.len() == 1); - assert!(matches!( - expressions[0], - Expression { - expr: Expr::Range( - Some(_), - None, - Some(_), - RangeOperator { - inclusion: RangeInclusion::RightExclusive, - .. - } - ), + + let expressions = &block[0]; + assert!(expressions.len() == 1); + assert!(matches!( + expressions[0], + Expression { + expr: Expr::Range( + Some(_), + None, + Some(_), + RangeOperator { + inclusion: RangeInclusion::RightExclusive, .. } - )) + ), + .. } - _ => panic!("No match"), - } + )) } #[test] @@ -301,27 +281,24 @@ mod range { assert!(err.is_none()); assert!(block.len() == 1); - match &block[0] { - Statement::Pipeline(Pipeline { expressions }) => { - assert!(expressions.len() == 1); - assert!(matches!( - expressions[0], - Expression { - expr: Expr::Range( - Some(_), - None, - Some(_), - RangeOperator { - inclusion: RangeInclusion::Inclusive, - .. - } - ), + + let expressions = &block[0]; + assert!(expressions.len() == 1); + assert!(matches!( + expressions[0], + Expression { + expr: Expr::Range( + Some(_), + None, + Some(_), + RangeOperator { + inclusion: RangeInclusion::Inclusive, .. } - )) + ), + .. } - _ => panic!("No match"), - } + )) } #[test] @@ -333,27 +310,24 @@ mod range { assert!(err.is_none()); assert!(block.len() == 1); - match &block[0] { - Statement::Pipeline(Pipeline { expressions }) => { - assert!(expressions.len() == 1); - assert!(matches!( - expressions[0], - Expression { - expr: Expr::Range( - Some(_), - None, - Some(_), - RangeOperator { - inclusion: RangeInclusion::RightExclusive, - .. - } - ), + + let expressions = &block[0]; + assert!(expressions.len() == 1); + assert!(matches!( + expressions[0], + Expression { + expr: Expr::Range( + Some(_), + None, + Some(_), + RangeOperator { + inclusion: RangeInclusion::RightExclusive, .. } - )) + ), + .. } - _ => panic!("No match"), - } + )) } #[test] @@ -367,27 +341,24 @@ mod range { assert!(err.is_none()); assert!(block.len() == 2); - match &block[1] { - Statement::Pipeline(Pipeline { expressions }) => { - assert!(expressions.len() == 1); - assert!(matches!( - expressions[0], - Expression { - expr: Expr::Range( - Some(_), - None, - Some(_), - RangeOperator { - inclusion: RangeInclusion::Inclusive, - .. - } - ), + + let expressions = &block[1]; + assert!(expressions.len() == 1); + assert!(matches!( + expressions[0], + Expression { + expr: Expr::Range( + Some(_), + None, + Some(_), + RangeOperator { + inclusion: RangeInclusion::Inclusive, .. } - )) + ), + .. } - _ => panic!("No match"), - } + )) } #[test] @@ -401,27 +372,24 @@ mod range { assert!(err.is_none()); assert!(block.len() == 2); - match &block[1] { - Statement::Pipeline(Pipeline { expressions }) => { - assert!(expressions.len() == 1); - assert!(matches!( - expressions[0], - Expression { - expr: Expr::Range( - Some(_), - None, - Some(_), - RangeOperator { - inclusion: RangeInclusion::RightExclusive, - .. - } - ), + + let expressions = &block[1]; + assert!(expressions.len() == 1); + assert!(matches!( + expressions[0], + Expression { + expr: Expr::Range( + Some(_), + None, + Some(_), + RangeOperator { + inclusion: RangeInclusion::RightExclusive, .. } - )) + ), + .. } - _ => panic!("No match"), - } + )) } #[test] @@ -433,27 +401,24 @@ mod range { assert!(err.is_none()); assert!(block.len() == 1); - match &block[0] { - Statement::Pipeline(Pipeline { expressions }) => { - assert!(expressions.len() == 1); - assert!(matches!( - expressions[0], - Expression { - expr: Expr::Range( - Some(_), - None, - None, - RangeOperator { - inclusion: RangeInclusion::Inclusive, - .. - } - ), + + let expressions = &block[0]; + assert!(expressions.len() == 1); + assert!(matches!( + expressions[0], + Expression { + expr: Expr::Range( + Some(_), + None, + None, + RangeOperator { + inclusion: RangeInclusion::Inclusive, .. } - )) + ), + .. } - _ => panic!("No match"), - } + )) } #[test] @@ -465,27 +430,24 @@ mod range { assert!(err.is_none()); assert!(block.len() == 1); - match &block[0] { - Statement::Pipeline(Pipeline { expressions }) => { - assert!(expressions.len() == 1); - assert!(matches!( - expressions[0], - Expression { - expr: Expr::Range( - None, - None, - Some(_), - RangeOperator { - inclusion: RangeInclusion::Inclusive, - .. - } - ), + + let expressions = &block[0]; + assert!(expressions.len() == 1); + assert!(matches!( + expressions[0], + Expression { + expr: Expr::Range( + None, + None, + Some(_), + RangeOperator { + inclusion: RangeInclusion::Inclusive, .. } - )) + ), + .. } - _ => panic!("No match"), - } + )) } #[test] @@ -497,27 +459,24 @@ mod range { assert!(err.is_none()); assert!(block.len() == 1); - match &block[0] { - Statement::Pipeline(Pipeline { expressions }) => { - assert!(expressions.len() == 1); - assert!(matches!( - expressions[0], - Expression { - expr: Expr::Range( - Some(_), - None, - Some(_), - RangeOperator { - inclusion: RangeInclusion::Inclusive, - .. - } - ), + + let expressions = &block[0]; + assert!(expressions.len() == 1); + assert!(matches!( + expressions[0], + Expression { + expr: Expr::Range( + Some(_), + None, + Some(_), + RangeOperator { + inclusion: RangeInclusion::Inclusive, .. } - )) + ), + .. } - _ => panic!("No match"), - } + )) } #[test] @@ -529,27 +488,24 @@ mod range { assert!(err.is_none()); assert!(block.len() == 1); - match &block[0] { - Statement::Pipeline(Pipeline { expressions }) => { - assert!(expressions.len() == 1); - assert!(matches!( - expressions[0], - Expression { - expr: Expr::Range( - Some(_), - Some(_), - Some(_), - RangeOperator { - inclusion: RangeInclusion::Inclusive, - .. - } - ), + + let expressions = &block[0]; + assert!(expressions.len() == 1); + assert!(matches!( + expressions[0], + Expression { + expr: Expr::Range( + Some(_), + Some(_), + Some(_), + RangeOperator { + inclusion: RangeInclusion::Inclusive, .. } - )) + ), + .. } - _ => panic!("No match"), - } + )) } #[test] diff --git a/crates/nu-protocol/src/ast/block.rs b/crates/nu-protocol/src/ast/block.rs index 79a1f150ce..43aa5e7eb4 100644 --- a/crates/nu-protocol/src/ast/block.rs +++ b/crates/nu-protocol/src/ast/block.rs @@ -2,12 +2,12 @@ use std::ops::{Index, IndexMut}; use crate::{Signature, Span, VarId}; -use super::Statement; +use super::Pipeline; #[derive(Debug, Clone)] pub struct Block { pub signature: Box, - pub stmts: Vec, + pub pipelines: Vec, pub captures: Vec, pub redirect_env: bool, pub span: Option, // None option encodes no span to avoid using test_span() @@ -15,25 +15,25 @@ pub struct Block { impl Block { pub fn len(&self) -> usize { - self.stmts.len() + self.pipelines.len() } pub fn is_empty(&self) -> bool { - self.stmts.is_empty() + self.pipelines.is_empty() } } impl Index for Block { - type Output = Statement; + type Output = Pipeline; fn index(&self, index: usize) -> &Self::Output { - &self.stmts[index] + &self.pipelines[index] } } impl IndexMut for Block { fn index_mut(&mut self, index: usize) -> &mut Self::Output { - &mut self.stmts[index] + &mut self.pipelines[index] } } @@ -47,7 +47,7 @@ impl Block { pub fn new() -> Self { Self { signature: Box::new(Signature::new("")), - stmts: vec![], + pipelines: vec![], captures: vec![], redirect_env: false, span: None, @@ -57,12 +57,12 @@ impl Block { impl From for Block where - T: Iterator, + T: Iterator, { - fn from(stmts: T) -> Self { + fn from(pipelines: T) -> Self { Self { signature: Box::new(Signature::new("")), - stmts: stmts.collect(), + pipelines: pipelines.collect(), captures: vec![], redirect_env: false, span: None, diff --git a/crates/nu-protocol/src/ast/expression.rs b/crates/nu-protocol/src/ast/expression.rs index 8351dfb842..c678c89773 100644 --- a/crates/nu-protocol/src/ast/expression.rs +++ b/crates/nu-protocol/src/ast/expression.rs @@ -1,4 +1,4 @@ -use super::{Expr, Operator, Statement}; +use super::{Expr, Operator}; use crate::ast::ImportPattern; use crate::{engine::StateWorkingSet, BlockId, Signature, Span, Type, VarId, IN_VARIABLE_ID}; @@ -116,7 +116,7 @@ impl Expression { return true; } - if let Some(Statement::Pipeline(pipeline)) = block.stmts.get(0) { + if let Some(pipeline) = block.pipelines.get(0) { match pipeline.expressions.get(0) { Some(expr) => expr.has_in_variable(working_set), None => false, @@ -218,7 +218,7 @@ impl Expression { Expr::RowCondition(block_id) | Expr::Subexpression(block_id) => { let block = working_set.get_block(*block_id); - if let Some(Statement::Pipeline(pipeline)) = block.stmts.get(0) { + if let Some(pipeline) = block.pipelines.get(0) { if let Some(expr) = pipeline.expressions.get(0) { expr.has_in_variable(working_set) } else { @@ -261,7 +261,7 @@ impl Expression { Expr::Block(block_id) => { let block = working_set.get_block(*block_id); - let new_expr = if let Some(Statement::Pipeline(pipeline)) = block.stmts.get(0) { + let new_expr = if let Some(pipeline) = block.pipelines.get(0) { if let Some(expr) = pipeline.expressions.get(0) { let mut new_expr = expr.clone(); new_expr.replace_in_variable(working_set, new_var_id); @@ -276,7 +276,7 @@ impl Expression { let block = working_set.get_block_mut(*block_id); if let Some(new_expr) = new_expr { - if let Some(Statement::Pipeline(pipeline)) = block.stmts.get_mut(0) { + if let Some(pipeline) = block.pipelines.get_mut(0) { if let Some(expr) = pipeline.expressions.get_mut(0) { *expr = new_expr } @@ -353,7 +353,7 @@ impl Expression { Expr::RowCondition(block_id) | Expr::Subexpression(block_id) => { let block = working_set.get_block(*block_id); - let new_expr = if let Some(Statement::Pipeline(pipeline)) = block.stmts.get(0) { + let new_expr = if let Some(pipeline) = block.pipelines.get(0) { if let Some(expr) = pipeline.expressions.get(0) { let mut new_expr = expr.clone(); new_expr.replace_in_variable(working_set, new_var_id); @@ -368,7 +368,7 @@ impl Expression { let block = working_set.get_block_mut(*block_id); if let Some(new_expr) = new_expr { - if let Some(Statement::Pipeline(pipeline)) = block.stmts.get_mut(0) { + if let Some(pipeline) = block.pipelines.get_mut(0) { if let Some(expr) = pipeline.expressions.get_mut(0) { *expr = new_expr } @@ -420,11 +420,9 @@ impl Expression { Expr::Block(block_id) => { let mut block = working_set.get_block(*block_id).clone(); - for stmt in block.stmts.iter_mut() { - if let Statement::Pipeline(pipeline) = stmt { - for expr in pipeline.expressions.iter_mut() { - expr.replace_span(working_set, replaced, new_span) - } + for pipeline in block.pipelines.iter_mut() { + for expr in pipeline.expressions.iter_mut() { + expr.replace_span(working_set, replaced, new_span) } } @@ -497,11 +495,9 @@ impl Expression { Expr::RowCondition(block_id) | Expr::Subexpression(block_id) => { let mut block = working_set.get_block(*block_id).clone(); - for stmt in block.stmts.iter_mut() { - if let Statement::Pipeline(pipeline) = stmt { - for expr in pipeline.expressions.iter_mut() { - expr.replace_span(working_set, replaced, new_span) - } + for pipeline in block.pipelines.iter_mut() { + for expr in pipeline.expressions.iter_mut() { + expr.replace_span(working_set, replaced, new_span) } } diff --git a/crates/nu-protocol/src/ast/mod.rs b/crates/nu-protocol/src/ast/mod.rs index 67c9ce76e9..f34cf24810 100644 --- a/crates/nu-protocol/src/ast/mod.rs +++ b/crates/nu-protocol/src/ast/mod.rs @@ -6,7 +6,6 @@ mod expression; mod import_pattern; mod operator; mod pipeline; -mod statement; pub use block::*; pub use call::*; @@ -16,4 +15,3 @@ pub use expression::*; pub use import_pattern::*; pub use operator::*; pub use pipeline::*; -pub use statement::*; diff --git a/crates/nu-protocol/src/ast/pipeline.rs b/crates/nu-protocol/src/ast/pipeline.rs index 1f5652fa41..369e49a3a0 100644 --- a/crates/nu-protocol/src/ast/pipeline.rs +++ b/crates/nu-protocol/src/ast/pipeline.rs @@ -1,3 +1,5 @@ +use std::ops::{Index, IndexMut}; + use crate::ast::Expression; #[derive(Debug, Clone)] @@ -21,4 +23,26 @@ impl Pipeline { pub fn from_vec(expressions: Vec) -> Pipeline { Self { expressions } } + + pub fn len(&self) -> usize { + self.expressions.len() + } + + pub fn is_empty(&self) -> bool { + self.expressions.is_empty() + } +} + +impl Index for Pipeline { + type Output = Expression; + + fn index(&self, index: usize) -> &Self::Output { + &self.expressions[index] + } +} + +impl IndexMut for Pipeline { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + &mut self.expressions[index] + } } diff --git a/crates/nu-protocol/src/ast/statement.rs b/crates/nu-protocol/src/ast/statement.rs deleted file mode 100644 index 5fa7faef12..0000000000 --- a/crates/nu-protocol/src/ast/statement.rs +++ /dev/null @@ -1,8 +0,0 @@ -use super::Pipeline; -use crate::DeclId; - -#[derive(Debug, Clone)] -pub enum Statement { - Declaration(DeclId), - Pipeline(Pipeline), -} diff --git a/src/main.rs b/src/main.rs index e45e8adf11..2259c4a7a2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,7 +17,7 @@ use nu_command::{create_default_context, BufferedReader}; use nu_engine::{get_full_help, CallExt}; use nu_parser::parse; use nu_protocol::{ - ast::{Call, Expr, Expression, Pipeline, Statement}, + ast::{Call, Expr, Expression}, engine::{Command, EngineState, Stack, StateWorkingSet}, Category, Example, IntoPipelineData, PipelineData, RawStream, ShellError, Signature, Span, Spanned, SyntaxShape, Value, CONFIG_VARIABLE_ID, @@ -241,11 +241,11 @@ fn parse_commandline_args( ); // We should have a successful parse now - if let Some(Statement::Pipeline(Pipeline { expressions })) = block.stmts.get(0) { + if let Some(pipeline) = block.pipelines.get(0) { if let Some(Expression { expr: Expr::Call(call), .. - }) = expressions.get(0) + }) = pipeline.expressions.get(0) { let redirect_stdin = call.get_named_arg("stdin"); let login_shell = call.get_named_arg("login");