Remove statements, replaced by pipelines (#4482)

This commit is contained in:
JT 2022-02-15 14:31:14 -05:00 committed by GitHub
parent 66669d7839
commit 56b3fc61a3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 660 additions and 750 deletions

View file

@ -1,7 +1,7 @@
use nu_engine::eval_block; use nu_engine::eval_block;
use nu_parser::{flatten_expression, parse, trim_quotes, FlatShape}; use nu_parser::{flatten_expression, parse, trim_quotes, FlatShape};
use nu_protocol::{ use nu_protocol::{
ast::{Expr, Statement}, ast::Expr,
engine::{EngineState, Stack, StateWorkingSet}, engine::{EngineState, Stack, StateWorkingSet},
PipelineData, Span, Value, CONFIG_VARIABLE_ID, PipelineData, Span, Value, CONFIG_VARIABLE_ID,
}; };
@ -174,228 +174,214 @@ impl NuCompleter {
let pos = offset + pos; let pos = offset + pos;
let (output, _err) = parse(&mut working_set, Some("completer"), line.as_bytes(), false); let (output, _err) = parse(&mut working_set, Some("completer"), line.as_bytes(), false);
for stmt in output.stmts.into_iter() { for pipeline in output.pipelines.into_iter() {
if let Statement::Pipeline(pipeline) = stmt { for expr in pipeline.expressions {
for expr in pipeline.expressions { let flattened: Vec<_> = flatten_expression(&working_set, &expr);
let flattened: Vec<_> = flatten_expression(&working_set, &expr);
for (flat_idx, flat) in flattened.iter().enumerate() { for (flat_idx, flat) in flattened.iter().enumerate() {
if pos >= flat.0.start && pos < flat.0.end { if pos >= flat.0.start && pos < flat.0.end {
let new_span = Span { let new_span = Span {
start: flat.0.start, start: flat.0.start,
end: flat.0.end - 1, end: flat.0.end - 1,
}; };
let mut prefix = working_set.get_span_contents(flat.0).to_vec(); let mut prefix = working_set.get_span_contents(flat.0).to_vec();
prefix.remove(pos - flat.0.start); prefix.remove(pos - flat.0.start);
if prefix.starts_with(b"$") { if prefix.starts_with(b"$") {
return self.complete_variables( return self.complete_variables(
&working_set, &working_set,
&prefix, &prefix,
new_span, new_span,
offset, offset,
); );
} }
if prefix.starts_with(b"-") { if prefix.starts_with(b"-") {
// this might be a flag, let's see // this might be a flag, let's see
if let Expr::Call(call) = &expr.expr { if let Expr::Call(call) = &expr.expr {
let decl = working_set.get_decl(call.decl_id); let decl = working_set.get_decl(call.decl_id);
let sig = decl.signature(); let sig = decl.signature();
let mut output = vec![]; let mut output = vec![];
for named in &sig.named { for named in &sig.named {
let mut named = named.long.as_bytes().to_vec(); let mut named = named.long.as_bytes().to_vec();
named.insert(0, b'-'); named.insert(0, b'-');
named.insert(0, b'-'); named.insert(0, b'-');
if named.starts_with(&prefix) { if named.starts_with(&prefix) {
output.push(( output.push((
reedline::Span { reedline::Span {
start: new_span.start - offset, start: new_span.start - offset,
end: new_span.end - 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,
}, },
offset, String::from_utf8_lossy(&named).to_string(),
false, ));
)
} else {
vec![]
};
if !subcommands.is_empty() {
return subcommands;
} }
}
return output;
}
}
let commands = match &flat.1 {
if matches!(flat_shape, nu_parser::FlatShape::External) FlatShape::Custom(custom_completion) => {
|| matches!( //let prefix = working_set.get_span_contents(flat.0).to_vec();
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![]
};
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() { // we're in a gap or at a command
Ok(s) => s, self.complete_commands(&working_set, new_span, offset, true)
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 { } else {
vec![] 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 { let cwd = if let Some(d) = self.engine_state.env_vars.get("PWD") {
if is_executable::is_executable(expanded) { match d.as_string() {
(x.0, format!("^{}", x.1)) Ok(s) => s,
} else { Err(_) => "".to_string(),
(x.0, x.1) }
} } 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 { } else {
(x.0, x.1) (x.0, x.1)
} }
@ -405,23 +391,25 @@ impl NuCompleter {
} else { } else {
(x.0, x.1) (x.0, x.1)
} }
}) } else {
.map(move |x| { (x.0, x.1)
( }
reedline::Span { })
start: x.0.start - offset, .map(move |x| {
end: x.0.end - offset, (
}, reedline::Span {
x.1, start: x.0.start - offset,
) end: x.0.end - offset,
}) },
.chain(subcommands.into_iter()) x.1,
.chain(commands.into_iter()) )
.collect::<Vec<_>>(); })
//output.dedup_by(|a, b| a.1 == b.1); .chain(subcommands.into_iter())
.chain(commands.into_iter())
.collect::<Vec<_>>();
//output.dedup_by(|a, b| a.1 == b.1);
return output; return output;
}
} }
} }
} }

View file

@ -3,7 +3,7 @@ use std::collections::HashMap;
use std::io::Write; use std::io::Write;
use nu_path::expand_path_with; 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::engine::{EngineState, Stack};
use nu_protocol::{ use nu_protocol::{
IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, Range, ShellError, Span, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData, Range, ShellError, Span,
@ -471,21 +471,19 @@ pub fn eval_block(
block: &Block, block: &Block,
mut input: PipelineData, mut input: PipelineData,
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
let num_stmts = block.stmts.len(); let num_pipelines = block.len();
for (stmt_idx, stmt) in block.stmts.iter().enumerate() { for (pipeline_idx, pipeline) in block.pipelines.iter().enumerate() {
if let Statement::Pipeline(pipeline) = stmt { for (i, elem) in pipeline.expressions.iter().enumerate() {
for (i, elem) in pipeline.expressions.iter().enumerate() { input = eval_expression_with_input(
input = eval_expression_with_input( engine_state,
engine_state, stack,
stack, elem,
elem, input,
input, i == pipeline.expressions.len() - 1,
i == pipeline.expressions.len() - 1, )?
)?
}
} }
if stmt_idx < (num_stmts) - 1 { if pipeline_idx < (num_pipelines) - 1 {
match input { match input {
PipelineData::Value(Value::Nothing { .. }, ..) => {} PipelineData::Value(Value::Nothing { .. }, ..) => {}
_ => { _ => {
@ -551,15 +549,13 @@ pub fn eval_block_with_redirect(
block: &Block, block: &Block,
mut input: PipelineData, mut input: PipelineData,
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
let num_stmts = block.stmts.len(); let num_pipelines = block.len();
for (stmt_idx, stmt) in block.stmts.iter().enumerate() { for (pipeline_idx, pipeline) in block.pipelines.iter().enumerate() {
if let Statement::Pipeline(pipeline) = stmt { for elem in pipeline.expressions.iter() {
for elem in pipeline.expressions.iter() { input = eval_expression_with_input(engine_state, stack, elem, input, false)?
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 { match input {
PipelineData::Value(Value::Nothing { .. }, ..) => {} PipelineData::Value(Value::Nothing { .. }, ..) => {}
_ => { _ => {
@ -625,11 +621,9 @@ pub fn eval_subexpression(
block: &Block, block: &Block,
mut input: PipelineData, mut input: PipelineData,
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
for stmt in block.stmts.iter() { for pipeline in block.pipelines.iter() {
if let Statement::Pipeline(pipeline) = stmt { for expr in pipeline.expressions.iter() {
for expr in pipeline.expressions.iter() { input = eval_expression_with_input(engine_state, stack, expr, input, false)?
input = eval_expression_with_input(engine_state, stack, expr, input, false)?
}
} }
} }

View file

@ -27,10 +27,6 @@ pub enum ParseError {
#[diagnostic(code(nu::parser::unclosed_delimiter), url(docsrs))] #[diagnostic(code(nu::parser::unclosed_delimiter), url(docsrs))]
Unclosed(String, #[label("unclosed {0}")] Span), 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.")] #[error("Parse mismatch during operation.")]
#[diagnostic(code(nu::parser::parse_mismatch), url(docsrs))] #[diagnostic(code(nu::parser::parse_mismatch), url(docsrs))]
Expected(String, #[label("expected {0}")] Span), 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." "'{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")] #[error("Incorrect value")]
#[diagnostic(code(nu::parser::incorrect_value), url(docsrs), help("{2}"))] #[diagnostic(code(nu::parser::incorrect_value), url(docsrs), help("{2}"))]

View file

@ -1,6 +1,4 @@
use nu_protocol::ast::{ use nu_protocol::ast::{Block, Expr, Expression, ImportPatternMember, PathMember, Pipeline};
Block, Expr, Expression, ImportPatternMember, PathMember, Pipeline, Statement,
};
use nu_protocol::{engine::StateWorkingSet, Span}; use nu_protocol::{engine::StateWorkingSet, Span};
use std::fmt::{Display, Formatter, Result}; 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)> { pub fn flatten_block(working_set: &StateWorkingSet, block: &Block) -> Vec<(Span, FlatShape)> {
let mut output = vec![]; let mut output = vec![];
for stmt in &block.stmts { for pipeline in &block.pipelines {
output.extend(flatten_statement(working_set, stmt)); output.extend(flatten_pipeline(working_set, pipeline));
} }
output 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( pub fn flatten_expression(
working_set: &StateWorkingSet, working_set: &StateWorkingSet,
expr: &Expression, expr: &Expression,

View file

@ -8,9 +8,7 @@ mod parser;
mod type_check; mod type_check;
pub use errors::ParseError; pub use errors::ParseError;
pub use flatten::{ pub use flatten::{flatten_block, flatten_expression, flatten_pipeline, FlatShape};
flatten_block, flatten_expression, flatten_pipeline, flatten_statement, FlatShape,
};
pub use known_external::KnownExternal; pub use known_external::KnownExternal;
pub use lex::{lex, Token, TokenContents}; pub use lex::{lex, Token, TokenContents};
pub use lite_parse::{lite_parse, LiteBlock}; pub use lite_parse::{lite_parse, LiteBlock};

View file

@ -31,17 +31,17 @@ impl LiteCommand {
} }
#[derive(Debug)] #[derive(Debug)]
pub struct LiteStatement { pub struct LitePipeline {
pub commands: Vec<LiteCommand>, pub commands: Vec<LiteCommand>,
} }
impl Default for LiteStatement { impl Default for LitePipeline {
fn default() -> Self { fn default() -> Self {
Self::new() Self::new()
} }
} }
impl LiteStatement { impl LitePipeline {
pub fn new() -> Self { pub fn new() -> Self {
Self { commands: vec![] } Self { commands: vec![] }
} }
@ -57,7 +57,7 @@ impl LiteStatement {
#[derive(Debug)] #[derive(Debug)]
pub struct LiteBlock { pub struct LiteBlock {
pub block: Vec<LiteStatement>, pub block: Vec<LitePipeline>,
} }
impl Default for LiteBlock { impl Default for LiteBlock {
@ -71,7 +71,7 @@ impl LiteBlock {
Self { block: vec![] } Self { block: vec![] }
} }
pub fn push(&mut self, pipeline: LiteStatement) { pub fn push(&mut self, pipeline: LitePipeline) {
self.block.push(pipeline); self.block.push(pipeline);
} }
@ -82,7 +82,7 @@ impl LiteBlock {
pub fn lite_parse(tokens: &[Token]) -> (LiteBlock, Option<ParseError>) { pub fn lite_parse(tokens: &[Token]) -> (LiteBlock, Option<ParseError>) {
let mut block = LiteBlock::new(); 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 curr_command = LiteCommand::new();
let mut last_token = TokenContents::Eol; let mut last_token = TokenContents::Eol;
@ -117,7 +117,7 @@ pub fn lite_parse(tokens: &[Token]) -> (LiteBlock, Option<ParseError>) {
if !curr_pipeline.is_empty() { if !curr_pipeline.is_empty() {
block.push(curr_pipeline); block.push(curr_pipeline);
curr_pipeline = LiteStatement::new(); curr_pipeline = LitePipeline::new();
} }
} }
@ -138,7 +138,7 @@ pub fn lite_parse(tokens: &[Token]) -> (LiteBlock, Option<ParseError>) {
if !curr_pipeline.is_empty() { if !curr_pipeline.is_empty() {
block.push(curr_pipeline); block.push(curr_pipeline);
curr_pipeline = LiteStatement::new(); curr_pipeline = LitePipeline::new();
} }
last_token = TokenContents::Semicolon; last_token = TokenContents::Semicolon;

View file

@ -2,7 +2,7 @@ use nu_path::canonicalize_with;
use nu_protocol::{ use nu_protocol::{
ast::{ ast::{
Block, Call, Expr, Expression, ImportPattern, ImportPatternHead, ImportPatternMember, Block, Call, Expr, Expression, ImportPattern, ImportPatternHead, ImportPatternMember,
Pipeline, Statement, Pipeline,
}, },
engine::StateWorkingSet, engine::StateWorkingSet,
span, Exportable, Overlay, PositionalArg, Span, SyntaxShape, Type, CONFIG_VARIABLE_ID, span, Exportable, Overlay, PositionalArg, Span, SyntaxShape, Type, CONFIG_VARIABLE_ID,
@ -14,7 +14,7 @@ use crate::{
lex, lite_parse, lex, lite_parse,
lite_parse::LiteCommand, lite_parse::LiteCommand,
parser::{ 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_internal_call, parse_multispan_value, parse_signature, parse_string,
parse_var_with_opt_type, trim_quotes, parse_var_with_opt_type, trim_quotes,
}, },
@ -245,7 +245,7 @@ fn build_usage(working_set: &StateWorkingSet, spans: &[Span]) -> String {
pub fn parse_def( pub fn parse_def(
working_set: &mut StateWorkingSet, working_set: &mut StateWorkingSet,
lite_command: &LiteCommand, lite_command: &LiteCommand,
) -> (Statement, Option<ParseError>) { ) -> (Pipeline, Option<ParseError>) {
let spans = &lite_command.parts[..]; let spans = &lite_command.parts[..];
let usage = build_usage(working_set, &lite_command.comments); 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(); let def_call = working_set.get_span_contents(spans[0]).to_vec();
if def_call != b"def" && def_call != b"def-env" { if def_call != b"def" && def_call != b"def-env" {
return ( return (
garbage_statement(spans), garbage_pipeline(spans),
Some(ParseError::UnknownState( Some(ParseError::UnknownState(
"internal error: Wrong call name for def function".into(), "internal error: Wrong call name for def function".into(),
span(spans), span(spans),
@ -270,7 +270,7 @@ pub fn parse_def(
let (call, call_span) = match working_set.find_decl(&def_call) { let (call, call_span) = match working_set.find_decl(&def_call) {
None => { None => {
return ( return (
garbage_statement(spans), garbage_pipeline(spans),
Some(ParseError::UnknownState( Some(ParseError::UnknownState(
"internal error: def declaration not found".into(), "internal error: def declaration not found".into(),
span(spans), span(spans),
@ -308,12 +308,12 @@ pub fn parse_def(
err = check_call(call_span, &sig, &call).or(err); err = check_call(call_span, &sig, &call).or(err);
if err.is_some() || call.has_flag("help") { if err.is_some() || call.has_flag("help") {
return ( return (
Statement::Pipeline(Pipeline::from_vec(vec![Expression { Pipeline::from_vec(vec![Expression {
expr: Expr::Call(call), expr: Expr::Call(call),
span: call_span, span: call_span,
ty: Type::Unknown, ty: Type::Unknown,
custom_completion: None, custom_completion: None,
}])), }]),
err, 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), expr: Expr::Call(call),
span: call_span, span: call_span,
ty: Type::Unknown, ty: Type::Unknown,
custom_completion: None, custom_completion: None,
}])), }]),
error, error,
) )
} }
@ -378,7 +378,7 @@ pub fn parse_def(
pub fn parse_extern( pub fn parse_extern(
working_set: &mut StateWorkingSet, working_set: &mut StateWorkingSet,
lite_command: &LiteCommand, lite_command: &LiteCommand,
) -> (Statement, Option<ParseError>) { ) -> (Pipeline, Option<ParseError>) {
let spans = &lite_command.parts[..]; let spans = &lite_command.parts[..];
let mut error = None; let mut error = None;
@ -390,7 +390,7 @@ pub fn parse_extern(
let extern_call = working_set.get_span_contents(spans[0]).to_vec(); let extern_call = working_set.get_span_contents(spans[0]).to_vec();
if extern_call != b"extern" { if extern_call != b"extern" {
return ( return (
garbage_statement(spans), garbage_pipeline(spans),
Some(ParseError::UnknownState( Some(ParseError::UnknownState(
"internal error: Wrong call name for extern function".into(), "internal error: Wrong call name for extern function".into(),
span(spans), span(spans),
@ -404,7 +404,7 @@ pub fn parse_extern(
let (call, call_span) = match working_set.find_decl(&extern_call) { let (call, call_span) = match working_set.find_decl(&extern_call) {
None => { None => {
return ( return (
garbage_statement(spans), garbage_pipeline(spans),
Some(ParseError::UnknownState( Some(ParseError::UnknownState(
"internal error: def declaration not found".into(), "internal error: def declaration not found".into(),
span(spans), 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), expr: Expr::Call(call),
span: call_span, span: call_span,
ty: Type::Unknown, ty: Type::Unknown,
custom_completion: None, custom_completion: None,
}])), }]),
error, error,
) )
} }
@ -479,15 +479,12 @@ pub fn parse_extern(
pub fn parse_alias( pub fn parse_alias(
working_set: &mut StateWorkingSet, working_set: &mut StateWorkingSet,
spans: &[Span], spans: &[Span],
) -> (Statement, Option<ParseError>) { ) -> (Pipeline, Option<ParseError>) {
let name = working_set.get_span_contents(spans[0]); let name = working_set.get_span_contents(spans[0]);
if name == b"alias" { if name == b"alias" {
if let Some((span, err)) = check_name(working_set, spans) { if let Some((span, err)) = check_name(working_set, spans) {
return ( return (Pipeline::from_vec(vec![garbage(*span)]), Some(err));
Statement::Pipeline(Pipeline::from_vec(vec![garbage(*span)])),
Some(err),
);
} }
if let Some(decl_id) = working_set.find_decl(b"alias") { if let Some(decl_id) = working_set.find_decl(b"alias") {
@ -512,19 +509,19 @@ pub fn parse_alias(
} }
return ( return (
Statement::Pipeline(Pipeline::from_vec(vec![Expression { Pipeline::from_vec(vec![Expression {
expr: Expr::Call(call), expr: Expr::Call(call),
span: span(spans), span: span(spans),
ty: Type::Unknown, ty: Type::Unknown,
custom_completion: None, custom_completion: None,
}])), }]),
None, None,
); );
} }
} }
( (
garbage_statement(spans), garbage_pipeline(spans),
Some(ParseError::InternalError( Some(ParseError::InternalError(
"Alias statement unparseable".into(), "Alias statement unparseable".into(),
span(spans), span(spans),
@ -535,14 +532,14 @@ pub fn parse_alias(
pub fn parse_export( pub fn parse_export(
working_set: &mut StateWorkingSet, working_set: &mut StateWorkingSet,
lite_command: &LiteCommand, lite_command: &LiteCommand,
) -> (Statement, Option<Exportable>, Option<ParseError>) { ) -> (Pipeline, Option<Exportable>, Option<ParseError>) {
let spans = &lite_command.parts[..]; let spans = &lite_command.parts[..];
let mut error = None; let mut error = None;
let export_span = if let Some(sp) = spans.get(0) { let export_span = if let Some(sp) = spans.get(0) {
if working_set.get_span_contents(*sp) != b"export" { if working_set.get_span_contents(*sp) != b"export" {
return ( return (
garbage_statement(spans), garbage_pipeline(spans),
None, None,
Some(ParseError::UnknownState( Some(ParseError::UnknownState(
"expected export statement".into(), "expected export statement".into(),
@ -554,7 +551,7 @@ pub fn parse_export(
*sp *sp
} else { } else {
return ( return (
garbage_statement(spans), garbage_pipeline(spans),
None, None,
Some(ParseError::UnknownState( Some(ParseError::UnknownState(
"got empty input for parsing export statement".into(), "got empty input for parsing export statement".into(),
@ -567,7 +564,7 @@ pub fn parse_export(
id id
} else { } else {
return ( return (
garbage_statement(spans), garbage_pipeline(spans),
None, None,
Some(ParseError::InternalError( Some(ParseError::InternalError(
"missing export command".into(), "missing export command".into(),
@ -591,14 +588,14 @@ pub fn parse_export(
comments: lite_command.comments.clone(), comments: lite_command.comments.clone(),
parts: spans[1..].to_vec(), 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); error = error.or(err);
let export_def_decl_id = if let Some(id) = working_set.find_decl(b"export def") { let export_def_decl_id = if let Some(id) = working_set.find_decl(b"export def") {
id id
} else { } else {
return ( return (
garbage_statement(spans), garbage_pipeline(spans),
None, None,
Some(ParseError::InternalError( Some(ParseError::InternalError(
"missing 'export def' command".into(), "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 // 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 {
if let Some(Expression { expr: Expr::Call(ref def_call),
expr: Expr::Call(ref def_call), ..
.. }) = pipeline.expressions.get(0)
}) = pipe.expressions.get(0) {
{ call = def_call.clone();
call = def_call.clone();
call.head = span(&spans[0..=1]); call.head = span(&spans[0..=1]);
call.decl_id = export_def_decl_id; 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..]),
))
});
}
} else { } else {
error = error.or_else(|| { error = error.or_else(|| {
Some(ParseError::InternalError( Some(ParseError::InternalError(
@ -658,7 +646,7 @@ pub fn parse_export(
comments: lite_command.comments.clone(), comments: lite_command.comments.clone(),
parts: spans[1..].to_vec(), 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); error = error.or(err);
let export_def_decl_id = if let Some(id) = working_set.find_decl(b"export def-env") 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 id
} else { } else {
return ( return (
garbage_statement(spans), garbage_pipeline(spans),
None, None,
Some(ParseError::InternalError( Some(ParseError::InternalError(
"missing 'export def-env' command".into(), "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 // 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 {
if let Some(Expression { expr: Expr::Call(ref def_call),
expr: Expr::Call(ref def_call), ..
.. }) = pipeline.expressions.get(0)
}) = pipe.expressions.get(0) {
{ call = def_call.clone();
call = def_call.clone();
call.head = span(&spans[0..=1]); call.head = span(&spans[0..=1]);
call.decl_id = export_def_decl_id; 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..]),
))
});
}
} else { } else {
error = error.or_else(|| { error = error.or_else(|| {
Some(ParseError::InternalError( Some(ParseError::InternalError(
@ -726,7 +705,7 @@ pub fn parse_export(
call.decl_id = id; call.decl_id = id;
} else { } else {
return ( return (
garbage_statement(spans), garbage_pipeline(spans),
None, None,
Some(ParseError::InternalError( Some(ParseError::InternalError(
"missing 'export env' command".into(), "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), expr: Expr::Call(call),
span: span(spans), span: span(spans),
ty: Type::Unknown, ty: Type::Unknown,
custom_completion: None, custom_completion: None,
}])), }]),
exportable, exportable,
error, error,
) )
@ -876,16 +855,16 @@ pub fn parse_module_block(
if pipeline.commands.len() == 1 { if pipeline.commands.len() == 1 {
let name = working_set.get_span_contents(pipeline.commands[0].parts[0]); 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" => { 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" => { 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: Currently, it is not possible to define a private env var.
// TODO: Exported env vars are usable iside the module only if correctly // 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` // 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". // since in the second case, the name of the env var would be $env."foo a".
b"export" => { b"export" => {
let (stmt, exportable, err) = let (pipe, exportable, err) =
parse_export(working_set, &pipeline.commands[0]); parse_export(working_set, &pipeline.commands[0]);
if err.is_none() { 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( Some(ParseError::UnexpectedKeyword(
"expected def or export keyword".into(), "expected def or export keyword".into(),
pipeline.commands[0].parts[0], pipeline.commands[0].parts[0],
@ -930,10 +909,10 @@ pub fn parse_module_block(
error = err; error = err;
} }
stmt pipeline
} else { } else {
error = Some(ParseError::Expected("not a pipeline".into(), span)); error = Some(ParseError::Expected("not a pipeline".into(), span));
garbage_statement(&[span]) garbage_pipeline(&[span])
} }
}) })
.into(); .into();
@ -946,7 +925,7 @@ pub fn parse_module_block(
pub fn parse_module( pub fn parse_module(
working_set: &mut StateWorkingSet, working_set: &mut StateWorkingSet,
spans: &[Span], spans: &[Span],
) -> (Statement, Option<ParseError>) { ) -> (Pipeline, Option<ParseError>) {
// TODO: Currently, module is closing over its parent scope (i.e., defs in the parent scope are // 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. // 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; start += 1;
} else { } else {
return ( return (
garbage_statement(spans), garbage_pipeline(spans),
Some(ParseError::Expected("block".into(), block_span)), 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), expr: Expr::Call(call),
span: span(spans), span: span(spans),
ty: Type::Unknown, ty: Type::Unknown,
custom_completion: None, custom_completion: None,
}])), }]),
error, error,
) )
} else { } else {
( (
garbage_statement(spans), garbage_pipeline(spans),
Some(ParseError::UnknownState( Some(ParseError::UnknownState(
"Expected structure: module <name> {}".into(), "Expected structure: module <name> {}".into(),
span(spans), span(spans),
@ -1031,10 +1010,10 @@ pub fn parse_module(
pub fn parse_use( pub fn parse_use(
working_set: &mut StateWorkingSet, working_set: &mut StateWorkingSet,
spans: &[Span], spans: &[Span],
) -> (Statement, Option<ParseError>) { ) -> (Pipeline, Option<ParseError>) {
if working_set.get_span_contents(spans[0]) != b"use" { if working_set.get_span_contents(spans[0]) != b"use" {
return ( return (
garbage_statement(spans), garbage_pipeline(spans),
Some(ParseError::UnknownState( Some(ParseError::UnknownState(
"internal error: Wrong call name for 'use' command".into(), "internal error: Wrong call name for 'use' command".into(),
span(spans), span(spans),
@ -1052,12 +1031,12 @@ pub fn parse_use(
err = check_call(call_span, &decl.signature(), &call).or(err); err = check_call(call_span, &decl.signature(), &call).or(err);
if err.is_some() || call.has_flag("help") { if err.is_some() || call.has_flag("help") {
return ( return (
Statement::Pipeline(Pipeline::from_vec(vec![Expression { Pipeline::from_vec(vec![Expression {
expr: Expr::Call(call), expr: Expr::Call(call),
span: call_span, span: call_span,
ty: Type::Unknown, ty: Type::Unknown,
custom_completion: None, custom_completion: None,
}])), }]),
err, err,
); );
} }
@ -1066,7 +1045,7 @@ pub fn parse_use(
} }
None => { None => {
return ( return (
garbage_statement(spans), garbage_pipeline(spans),
Some(ParseError::UnknownState( Some(ParseError::UnknownState(
"internal error: 'use' declaration not found".into(), "internal error: 'use' declaration not found".into(),
span(spans), span(spans),
@ -1080,7 +1059,7 @@ pub fn parse_use(
pattern pattern
} else { } else {
return ( return (
garbage_statement(spans), garbage_pipeline(spans),
Some(ParseError::UnknownState( Some(ParseError::UnknownState(
"internal error: Import pattern positional is not import pattern".into(), "internal error: Import pattern positional is not import pattern".into(),
call_span, call_span,
@ -1089,7 +1068,7 @@ pub fn parse_use(
} }
} else { } else {
return ( return (
garbage_statement(spans), garbage_pipeline(spans),
Some(ParseError::UnknownState( Some(ParseError::UnknownState(
"internal error: Missing required positional after call parsing".into(), "internal error: Missing required positional after call parsing".into(),
call_span, call_span,
@ -1117,12 +1096,12 @@ pub fn parse_use(
stem.to_string_lossy().to_string() stem.to_string_lossy().to_string()
} else { } else {
return ( return (
Statement::Pipeline(Pipeline::from_vec(vec![Expression { Pipeline::from_vec(vec![Expression {
expr: Expr::Call(call), expr: Expr::Call(call),
span: call_span, span: call_span,
ty: Type::Unknown, ty: Type::Unknown,
custom_completion: None, custom_completion: None,
}])), }]),
Some(ParseError::ModuleNotFound(spans[1])), Some(ParseError::ModuleNotFound(spans[1])),
); );
}; };
@ -1152,12 +1131,12 @@ pub fn parse_use(
) )
} else { } else {
return ( return (
Statement::Pipeline(Pipeline::from_vec(vec![Expression { Pipeline::from_vec(vec![Expression {
expr: Expr::Call(call), expr: Expr::Call(call),
span: call_span, span: call_span,
ty: Type::Unknown, ty: Type::Unknown,
custom_completion: None, custom_completion: None,
}])), }]),
Some(ParseError::ModuleNotFound(spans[1])), Some(ParseError::ModuleNotFound(spans[1])),
); );
} }
@ -1169,10 +1148,7 @@ pub fn parse_use(
(ImportPattern::new(), Overlay::new()) (ImportPattern::new(), Overlay::new())
} }
} else { } else {
return ( return (garbage_pipeline(spans), Some(ParseError::NonUtf8(spans[1])));
garbage_statement(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), expr: Expr::Call(call),
span: span(spans), span: span(spans),
ty: Type::Unknown, ty: Type::Unknown,
custom_completion: None, custom_completion: None,
}])), }]),
error, error,
) )
} }
@ -1241,10 +1217,10 @@ pub fn parse_use(
pub fn parse_hide( pub fn parse_hide(
working_set: &mut StateWorkingSet, working_set: &mut StateWorkingSet,
spans: &[Span], spans: &[Span],
) -> (Statement, Option<ParseError>) { ) -> (Pipeline, Option<ParseError>) {
if working_set.get_span_contents(spans[0]) != b"hide" { if working_set.get_span_contents(spans[0]) != b"hide" {
return ( return (
garbage_statement(spans), garbage_pipeline(spans),
Some(ParseError::UnknownState( Some(ParseError::UnknownState(
"internal error: Wrong call name for 'hide' command".into(), "internal error: Wrong call name for 'hide' command".into(),
span(spans), span(spans),
@ -1262,12 +1238,12 @@ pub fn parse_hide(
err = check_call(call_span, &decl.signature(), &call).or(err); err = check_call(call_span, &decl.signature(), &call).or(err);
if err.is_some() || call.has_flag("help") { if err.is_some() || call.has_flag("help") {
return ( return (
Statement::Pipeline(Pipeline::from_vec(vec![Expression { Pipeline::from_vec(vec![Expression {
expr: Expr::Call(call), expr: Expr::Call(call),
span: call_span, span: call_span,
ty: Type::Unknown, ty: Type::Unknown,
custom_completion: None, custom_completion: None,
}])), }]),
err, err,
); );
} }
@ -1276,7 +1252,7 @@ pub fn parse_hide(
} }
None => { None => {
return ( return (
garbage_statement(spans), garbage_pipeline(spans),
Some(ParseError::UnknownState( Some(ParseError::UnknownState(
"internal error: 'hide' declaration not found".into(), "internal error: 'hide' declaration not found".into(),
span(spans), span(spans),
@ -1290,7 +1266,7 @@ pub fn parse_hide(
pattern pattern
} else { } else {
return ( return (
garbage_statement(spans), garbage_pipeline(spans),
Some(ParseError::UnknownState( Some(ParseError::UnknownState(
"internal error: Import pattern positional is not import pattern".into(), "internal error: Import pattern positional is not import pattern".into(),
call_span, call_span,
@ -1299,7 +1275,7 @@ pub fn parse_hide(
} }
} else { } else {
return ( return (
garbage_statement(spans), garbage_pipeline(spans),
Some(ParseError::UnknownState( Some(ParseError::UnknownState(
"internal error: Missing required positional after call parsing".into(), "internal error: Missing required positional after call parsing".into(),
call_span, call_span,
@ -1339,7 +1315,7 @@ pub fn parse_hide(
} }
} else { } else {
return ( return (
garbage_statement(spans), garbage_pipeline(spans),
Some(ParseError::ModuleNotFound(spans[1])), 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), expr: Expr::Call(call),
span: span(spans), span: span(spans),
ty: Type::Unknown, ty: Type::Unknown,
custom_completion: None, custom_completion: None,
}])), }]),
error, error,
) )
} else { } else {
( (
garbage_statement(spans), garbage_pipeline(spans),
Some(ParseError::UnknownState( Some(ParseError::UnknownState(
"Expected structure: hide <name>".into(), "Expected structure: hide <name>".into(),
span(spans), span(spans),
@ -1449,15 +1425,12 @@ pub fn parse_hide(
pub fn parse_let( pub fn parse_let(
working_set: &mut StateWorkingSet, working_set: &mut StateWorkingSet,
spans: &[Span], spans: &[Span],
) -> (Statement, Option<ParseError>) { ) -> (Pipeline, Option<ParseError>) {
let name = working_set.get_span_contents(spans[0]); let name = working_set.get_span_contents(spans[0]);
if name == b"let" { if name == b"let" {
if let Some((span, err)) = check_name(working_set, spans) { if let Some((span, err)) = check_name(working_set, spans) {
return ( return (Pipeline::from_vec(vec![garbage(*span)]), Some(err));
Statement::Pipeline(Pipeline::from_vec(vec![garbage(*span)])),
Some(err),
);
} }
if let Some(decl_id) = working_set.find_decl(b"let") { if let Some(decl_id) = working_set.find_decl(b"let") {
@ -1511,12 +1484,12 @@ pub fn parse_let(
}); });
return ( return (
Statement::Pipeline(Pipeline::from_vec(vec![Expression { Pipeline::from_vec(vec![Expression {
expr: Expr::Call(call), expr: Expr::Call(call),
span: nu_protocol::span(spans), span: nu_protocol::span(spans),
ty: Type::Unknown, ty: Type::Unknown,
custom_completion: None, custom_completion: None,
}])), }]),
error, error,
); );
} }
@ -1525,20 +1498,20 @@ pub fn parse_let(
let (call, err) = parse_internal_call(working_set, spans[0], &spans[1..], decl_id); let (call, err) = parse_internal_call(working_set, spans[0], &spans[1..], decl_id);
return ( return (
Statement::Pipeline(Pipeline { Pipeline {
expressions: vec![Expression { expressions: vec![Expression {
expr: Expr::Call(call), expr: Expr::Call(call),
span: nu_protocol::span(spans), span: nu_protocol::span(spans),
ty: Type::Unknown, ty: Type::Unknown,
custom_completion: None, custom_completion: None,
}], }],
}), },
err, err,
); );
} }
} }
( (
garbage_statement(spans), garbage_pipeline(spans),
Some(ParseError::UnknownState( Some(ParseError::UnknownState(
"internal error: let statement unparseable".into(), "internal error: let statement unparseable".into(),
span(spans), span(spans),
@ -1549,7 +1522,7 @@ pub fn parse_let(
pub fn parse_source( pub fn parse_source(
working_set: &mut StateWorkingSet, working_set: &mut StateWorkingSet,
spans: &[Span], spans: &[Span],
) -> (Statement, Option<ParseError>) { ) -> (Pipeline, Option<ParseError>) {
let mut error = None; let mut error = None;
let name = working_set.get_span_contents(spans[0]); let name = working_set.get_span_contents(spans[0]);
@ -1580,12 +1553,12 @@ pub fn parse_source(
if err.is_some() { if err.is_some() {
// Unsuccessful parse of file // Unsuccessful parse of file
return ( return (
Statement::Pipeline(Pipeline::from_vec(vec![Expression { Pipeline::from_vec(vec![Expression {
expr: Expr::Call(call), expr: Expr::Call(call),
span: span(&spans[1..]), span: span(&spans[1..]),
ty: Type::Unknown, ty: Type::Unknown,
custom_completion: None, custom_completion: None,
}])), }]),
// Return the file parse error // Return the file parse error
err, err,
); );
@ -1605,12 +1578,12 @@ pub fn parse_source(
}); });
return ( return (
Statement::Pipeline(Pipeline::from_vec(vec![Expression { Pipeline::from_vec(vec![Expression {
expr: Expr::Call(call_with_block), expr: Expr::Call(call_with_block),
span: span(spans), span: span(spans),
ty: Type::Unknown, ty: Type::Unknown,
custom_completion: None, custom_completion: None,
}])), }]),
None, None,
); );
} }
@ -1619,25 +1592,22 @@ pub fn parse_source(
error = error.or(Some(ParseError::FileNotFound(filename, spans[1]))); error = error.or(Some(ParseError::FileNotFound(filename, spans[1])));
} }
} else { } else {
return ( return (garbage_pipeline(spans), Some(ParseError::NonUtf8(spans[1])));
garbage_statement(spans),
Some(ParseError::NonUtf8(spans[1])),
);
} }
} }
return ( return (
Statement::Pipeline(Pipeline::from_vec(vec![Expression { Pipeline::from_vec(vec![Expression {
expr: Expr::Call(call), expr: Expr::Call(call),
span: span(spans), span: span(spans),
ty: Type::Unknown, ty: Type::Unknown,
custom_completion: None, custom_completion: None,
}])), }]),
error, error,
); );
} }
} }
( (
garbage_statement(spans), garbage_pipeline(spans),
Some(ParseError::UnknownState( Some(ParseError::UnknownState(
"internal error: source statement unparseable".into(), "internal error: source statement unparseable".into(),
span(spans), span(spans),
@ -1649,7 +1619,7 @@ pub fn parse_source(
pub fn parse_register( pub fn parse_register(
working_set: &mut StateWorkingSet, working_set: &mut StateWorkingSet,
spans: &[Span], spans: &[Span],
) -> (Statement, Option<ParseError>) { ) -> (Pipeline, Option<ParseError>) {
use nu_plugin::{get_signature, EncodingType, PluginDeclaration}; use nu_plugin::{get_signature, EncodingType, PluginDeclaration};
use nu_protocol::Signature; use nu_protocol::Signature;
let cwd = working_set.get_cwd(); 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 // Maybe this is not necessary but it is a sanity check
if working_set.get_span_contents(spans[0]) != b"register" { if working_set.get_span_contents(spans[0]) != b"register" {
return ( return (
garbage_statement(spans), garbage_pipeline(spans),
Some(ParseError::UnknownState( Some(ParseError::UnknownState(
"internal error: Wrong call name for parse plugin function".into(), "internal error: Wrong call name for parse plugin function".into(),
span(spans), span(spans),
@ -1672,7 +1642,7 @@ pub fn parse_register(
let (call, call_span) = match working_set.find_decl(b"register") { let (call, call_span) = match working_set.find_decl(b"register") {
None => { None => {
return ( return (
garbage_statement(spans), garbage_pipeline(spans),
Some(ParseError::UnknownState( Some(ParseError::UnknownState(
"internal error: Register declaration not found".into(), "internal error: Register declaration not found".into(),
span(spans), span(spans),
@ -1688,12 +1658,12 @@ pub fn parse_register(
err = check_call(call_span, &decl.signature(), &call).or(err); err = check_call(call_span, &decl.signature(), &call).or(err);
if err.is_some() || call.has_flag("help") { if err.is_some() || call.has_flag("help") {
return ( return (
Statement::Pipeline(Pipeline::from_vec(vec![Expression { Pipeline::from_vec(vec![Expression {
expr: Expr::Call(call), expr: Expr::Call(call),
span: call_span, span: call_span,
ty: Type::Unknown, ty: Type::Unknown,
custom_completion: None, custom_completion: None,
}])), }]),
err, err,
); );
} }
@ -1779,12 +1749,12 @@ pub fn parse_register(
Ok(path) => Some(path), Ok(path) => Some(path),
Err(err) => { Err(err) => {
return ( return (
Statement::Pipeline(Pipeline::from_vec(vec![Expression { Pipeline::from_vec(vec![Expression {
expr: Expr::Call(call), expr: Expr::Call(call),
span: call_span, span: call_span,
ty: Type::Unknown, ty: Type::Unknown,
custom_completion: None, custom_completion: None,
}])), }]),
Some(err), Some(err),
); );
} }
@ -1829,12 +1799,12 @@ pub fn parse_register(
.err(); .err();
( (
Statement::Pipeline(Pipeline::from_vec(vec![Expression { Pipeline::from_vec(vec![Expression {
expr: Expr::Call(call), expr: Expr::Call(call),
span: call_span, span: call_span,
ty: Type::Nothing, ty: Type::Nothing,
custom_completion: None, custom_completion: None,
}])), }]),
error, error,
) )
} }

View file

@ -10,7 +10,6 @@ use nu_protocol::{
ast::{ ast::{
Block, Call, CellPath, Expr, Expression, FullCellPath, ImportPattern, ImportPatternHead, Block, Call, CellPath, Expr, Expression, FullCellPath, ImportPattern, ImportPatternHead,
ImportPatternMember, Operator, PathMember, Pipeline, RangeInclusion, RangeOperator, ImportPatternMember, Operator, PathMember, Pipeline, RangeInclusion, RangeOperator,
Statement,
}, },
engine::StateWorkingSet, engine::StateWorkingSet,
span, BlockId, Flag, PositionalArg, Signature, Span, Spanned, SyntaxShape, Type, Unit, VarId, span, BlockId, Flag, PositionalArg, Signature, Span, Spanned, SyntaxShape, Type, Unit, VarId,
@ -34,8 +33,8 @@ pub fn garbage(span: Span) -> Expression {
Expression::garbage(span) Expression::garbage(span)
} }
pub fn garbage_statement(spans: &[Span]) -> Statement { pub fn garbage_pipeline(spans: &[Span]) -> Pipeline {
Statement::Pipeline(Pipeline::from_vec(vec![garbage(span(spans))])) Pipeline::from_vec(vec![garbage(span(spans))])
} }
fn is_identifier_byte(b: u8) -> bool { fn is_identifier_byte(b: u8) -> bool {
@ -2293,7 +2292,7 @@ pub fn parse_row_condition(
let mut pipeline = Pipeline::new(); let mut pipeline = Pipeline::new();
pipeline.expressions.push(expression); pipeline.expressions.push(expression);
block.stmts.push(Statement::Pipeline(pipeline)); block.pipelines.push(pipeline);
block.signature.required_positional.push(PositionalArg { block.signature.required_positional.push(PositionalArg {
name: "$it".into(), name: "$it".into(),
@ -3413,31 +3412,43 @@ pub fn parse_expression(
match bytes { match bytes {
b"def" => ( b"def" => (
parse_call(working_set, &spans[pos..], expand_aliases, spans[0]).0, 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" => ( b"extern" => (
parse_call(working_set, &spans[pos..], expand_aliases, spans[0]).0, 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" => ( b"let" => (
parse_call(working_set, &spans[pos..], expand_aliases, spans[0]).0, 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" => ( b"alias" => (
parse_call(working_set, &spans[pos..], expand_aliases, spans[0]).0, 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" => ( b"module" => (
parse_call(working_set, &spans[pos..], expand_aliases, spans[0]).0, 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" => ( b"use" => (
parse_call(working_set, &spans[pos..], expand_aliases, spans[0]).0, 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" => ( b"source" => (
parse_call(working_set, &spans[pos..], expand_aliases, spans[0]).0, 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" => ( b"export" => (
parse_call(working_set, &spans[pos..], expand_aliases, spans[0]).0, parse_call(working_set, &spans[pos..], expand_aliases, spans[0]).0,
@ -3445,12 +3456,18 @@ pub fn parse_expression(
), ),
b"hide" => ( b"hide" => (
parse_call(working_set, &spans[pos..], expand_aliases, spans[0]).0, 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")] #[cfg(feature = "plugin")]
b"register" => ( b"register" => (
parse_call(working_set, &spans[pos..], expand_aliases, spans[0]).0, 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), b"for" => parse_for(working_set, spans),
@ -3464,9 +3481,9 @@ pub fn parse_expression(
if let Some(decl_id) = with_env { if let Some(decl_id) = with_env {
let mut block = Block::default(); let mut block = Block::default();
let ty = output.ty.clone(); let ty = output.ty.clone();
block.stmts = vec![Statement::Pipeline(Pipeline { block.pipelines = vec![Pipeline {
expressions: vec![output], expressions: vec![output],
})]; }];
let block_id = working_set.add_block(block); 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, working_set: &mut StateWorkingSet,
lite_command: &LiteCommand, lite_command: &LiteCommand,
) -> (Statement, Option<ParseError>) { ) -> (Pipeline, Option<ParseError>) {
let name = working_set.get_span_contents(lite_command.parts[0]); let name = working_set.get_span_contents(lite_command.parts[0]);
match name { match name {
@ -3542,14 +3559,14 @@ pub fn parse_statement(
b"let" => parse_let(working_set, &lite_command.parts), b"let" => parse_let(working_set, &lite_command.parts),
b"for" => { b"for" => {
let (expr, err) = parse_for(working_set, &lite_command.parts); 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"alias" => parse_alias(working_set, &lite_command.parts),
b"module" => parse_module(working_set, &lite_command.parts), b"module" => parse_module(working_set, &lite_command.parts),
b"use" => parse_use(working_set, &lite_command.parts), b"use" => parse_use(working_set, &lite_command.parts),
b"source" => parse_source(working_set, &lite_command.parts), b"source" => parse_source(working_set, &lite_command.parts),
b"export" => ( b"export" => (
garbage_statement(&lite_command.parts), garbage_pipeline(&lite_command.parts),
Some(ParseError::UnexpectedKeyword( Some(ParseError::UnexpectedKeyword(
"export".into(), "export".into(),
lite_command.parts[0], lite_command.parts[0],
@ -3560,7 +3577,7 @@ pub fn parse_statement(
b"register" => parse_register(working_set, &lite_command.parts), b"register" => parse_register(working_set, &lite_command.parts),
_ => { _ => {
let (expr, err) = parse_expression(working_set, &lite_command.parts, true); 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, expressions: output,
}) }
} else { } 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 idx == 0 {
if let Some(let_decl_id) = working_set.find_decl(b"let") { 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 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() {
for expr in pipeline.expressions.iter_mut() { if let Expression {
if let Expression { expr: Expr::Call(call),
expr: Expr::Call(call), ..
.. } = expr
} = expr {
if call.decl_id == let_decl_id
|| call.decl_id == let_env_decl_id
{ {
if call.decl_id == let_decl_id // Do an expansion
|| call.decl_id == let_env_decl_id if let Some(Expression {
expr: Expr::Keyword(_, _, expr),
..
}) = call.positional.get_mut(1)
{ {
// Do an expansion if expr.has_in_variable(working_set) {
if let Some(Expression { *expr = Box::new(wrap_expr_with_collect(
expr: Expr::Keyword(_, _, expr), working_set,
.. expr,
}) = call.positional.get_mut(1) ));
{
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; error = err;
} }
stmt pipeline
} }
}) })
.into(); .into();
@ -3778,15 +3794,9 @@ pub fn discover_captures_in_block(
} }
} }
for stmt in &block.stmts { for pipeline in &block.pipelines {
match stmt { let result = discover_captures_in_pipeline(working_set, pipeline, seen, seen_blocks);
Statement::Pipeline(pipeline) => { output.extend(&result);
let result =
discover_captures_in_pipeline(working_set, pipeline, seen, seen_blocks);
output.extend(&result);
}
Statement::Declaration(_) => {}
}
} }
output output
@ -4028,9 +4038,9 @@ fn wrap_expr_with_collect(working_set: &mut StateWorkingSet, expr: &Expression)
expr.replace_in_variable(working_set, var_id); expr.replace_in_variable(working_set, var_id);
let block = Block { let block = Block {
stmts: vec![Statement::Pipeline(Pipeline { pipelines: vec![Pipeline {
expressions: vec![expr], expressions: vec![expr],
})], }],
signature: Box::new(signature), signature: Box::new(signature),
..Default::default() ..Default::default()
}; };

View file

@ -109,7 +109,7 @@ fn separated_comments_dont_stack() -> Result<(), ParseError> {
} }
#[test] #[test]
fn multiple_statements() -> Result<(), ParseError> { fn multiple_pipelines() -> Result<(), ParseError> {
// Code: // Code:
// # A comment // # A comment
// let a = ( 3 + ( // let a = ( 3 + (

View file

@ -1,7 +1,7 @@
use nu_parser::ParseError; use nu_parser::ParseError;
use nu_parser::*; use nu_parser::*;
use nu_protocol::{ use nu_protocol::{
ast::{Expr, Expression, Pipeline, Statement}, ast::{Expr, Expression},
engine::{Command, EngineState, Stack, StateWorkingSet}, engine::{Command, EngineState, Stack, StateWorkingSet},
Signature, SyntaxShape, Signature, SyntaxShape,
}; };
@ -50,19 +50,15 @@ pub fn parse_int() {
assert!(err.is_none()); assert!(err.is_none());
assert!(block.len() == 1); assert!(block.len() == 1);
match &block[0] { let expressions = &block[0];
Statement::Pipeline(Pipeline { expressions }) => { assert!(expressions.len() == 1);
assert!(expressions.len() == 1); assert!(matches!(
assert!(matches!( expressions[0],
expressions[0], Expression {
Expression { expr: Expr::Int(3),
expr: Expr::Int(3), ..
..
}
))
} }
_ => panic!("No match"), ))
}
} }
#[test] #[test]
@ -78,19 +74,15 @@ pub fn parse_call() {
assert!(err.is_none()); assert!(err.is_none());
assert!(block.len() == 1); assert!(block.len() == 1);
match &block[0] { let expressions = &block[0];
Statement::Pipeline(Pipeline { expressions }) => { assert_eq!(expressions.len(), 1);
assert_eq!(expressions.len(), 1);
if let Expression { if let Expression {
expr: Expr::Call(call), expr: Expr::Call(call),
.. ..
} = &expressions[0] } = &expressions[0]
{ {
assert_eq!(call.decl_id, 0); assert_eq!(call.decl_id, 0);
}
}
_ => panic!("not a call"),
} }
} }
@ -186,19 +178,16 @@ fn test_nothing_comparisson_eq() {
assert!(err.is_none()); assert!(err.is_none());
assert!(block.len() == 1); assert!(block.len() == 1);
match &block[0] {
Statement::Pipeline(Pipeline { expressions }) => { let expressions = &block[0];
assert!(expressions.len() == 1); assert!(expressions.len() == 1);
assert!(matches!( assert!(matches!(
&expressions[0], &expressions[0],
Expression { Expression {
expr: Expr::BinaryOp(..), expr: Expr::BinaryOp(..),
.. ..
}
))
} }
_ => panic!("No match"), ))
}
} }
#[test] #[test]
@ -209,19 +198,16 @@ fn test_nothing_comparisson_neq() {
assert!(err.is_none()); assert!(err.is_none());
assert!(block.len() == 1); assert!(block.len() == 1);
match &block[0] {
Statement::Pipeline(Pipeline { expressions }) => { let expressions = &block[0];
assert!(expressions.len() == 1); assert!(expressions.len() == 1);
assert!(matches!( assert!(matches!(
&expressions[0], &expressions[0],
Expression { Expression {
expr: Expr::BinaryOp(..), expr: Expr::BinaryOp(..),
.. ..
}
))
} }
_ => panic!("No match"), ))
}
} }
mod range { mod range {
@ -237,27 +223,24 @@ mod range {
assert!(err.is_none()); assert!(err.is_none());
assert!(block.len() == 1); assert!(block.len() == 1);
match &block[0] {
Statement::Pipeline(Pipeline { expressions }) => { let expressions = &block[0];
assert!(expressions.len() == 1); assert!(expressions.len() == 1);
assert!(matches!( assert!(matches!(
expressions[0], expressions[0],
Expression { Expression {
expr: Expr::Range( expr: Expr::Range(
Some(_), Some(_),
None, None,
Some(_), Some(_),
RangeOperator { RangeOperator {
inclusion: RangeInclusion::Inclusive, inclusion: RangeInclusion::Inclusive,
..
}
),
.. ..
} }
)) ),
..
} }
_ => panic!("No match"), ))
}
} }
#[test] #[test]
@ -269,27 +252,24 @@ mod range {
assert!(err.is_none()); assert!(err.is_none());
assert!(block.len() == 1); assert!(block.len() == 1);
match &block[0] {
Statement::Pipeline(Pipeline { expressions }) => { let expressions = &block[0];
assert!(expressions.len() == 1); assert!(expressions.len() == 1);
assert!(matches!( assert!(matches!(
expressions[0], expressions[0],
Expression { Expression {
expr: Expr::Range( expr: Expr::Range(
Some(_), Some(_),
None, None,
Some(_), Some(_),
RangeOperator { RangeOperator {
inclusion: RangeInclusion::RightExclusive, inclusion: RangeInclusion::RightExclusive,
..
}
),
.. ..
} }
)) ),
..
} }
_ => panic!("No match"), ))
}
} }
#[test] #[test]
@ -301,27 +281,24 @@ mod range {
assert!(err.is_none()); assert!(err.is_none());
assert!(block.len() == 1); assert!(block.len() == 1);
match &block[0] {
Statement::Pipeline(Pipeline { expressions }) => { let expressions = &block[0];
assert!(expressions.len() == 1); assert!(expressions.len() == 1);
assert!(matches!( assert!(matches!(
expressions[0], expressions[0],
Expression { Expression {
expr: Expr::Range( expr: Expr::Range(
Some(_), Some(_),
None, None,
Some(_), Some(_),
RangeOperator { RangeOperator {
inclusion: RangeInclusion::Inclusive, inclusion: RangeInclusion::Inclusive,
..
}
),
.. ..
} }
)) ),
..
} }
_ => panic!("No match"), ))
}
} }
#[test] #[test]
@ -333,27 +310,24 @@ mod range {
assert!(err.is_none()); assert!(err.is_none());
assert!(block.len() == 1); assert!(block.len() == 1);
match &block[0] {
Statement::Pipeline(Pipeline { expressions }) => { let expressions = &block[0];
assert!(expressions.len() == 1); assert!(expressions.len() == 1);
assert!(matches!( assert!(matches!(
expressions[0], expressions[0],
Expression { Expression {
expr: Expr::Range( expr: Expr::Range(
Some(_), Some(_),
None, None,
Some(_), Some(_),
RangeOperator { RangeOperator {
inclusion: RangeInclusion::RightExclusive, inclusion: RangeInclusion::RightExclusive,
..
}
),
.. ..
} }
)) ),
..
} }
_ => panic!("No match"), ))
}
} }
#[test] #[test]
@ -367,27 +341,24 @@ mod range {
assert!(err.is_none()); assert!(err.is_none());
assert!(block.len() == 2); assert!(block.len() == 2);
match &block[1] {
Statement::Pipeline(Pipeline { expressions }) => { let expressions = &block[1];
assert!(expressions.len() == 1); assert!(expressions.len() == 1);
assert!(matches!( assert!(matches!(
expressions[0], expressions[0],
Expression { Expression {
expr: Expr::Range( expr: Expr::Range(
Some(_), Some(_),
None, None,
Some(_), Some(_),
RangeOperator { RangeOperator {
inclusion: RangeInclusion::Inclusive, inclusion: RangeInclusion::Inclusive,
..
}
),
.. ..
} }
)) ),
..
} }
_ => panic!("No match"), ))
}
} }
#[test] #[test]
@ -401,27 +372,24 @@ mod range {
assert!(err.is_none()); assert!(err.is_none());
assert!(block.len() == 2); assert!(block.len() == 2);
match &block[1] {
Statement::Pipeline(Pipeline { expressions }) => { let expressions = &block[1];
assert!(expressions.len() == 1); assert!(expressions.len() == 1);
assert!(matches!( assert!(matches!(
expressions[0], expressions[0],
Expression { Expression {
expr: Expr::Range( expr: Expr::Range(
Some(_), Some(_),
None, None,
Some(_), Some(_),
RangeOperator { RangeOperator {
inclusion: RangeInclusion::RightExclusive, inclusion: RangeInclusion::RightExclusive,
..
}
),
.. ..
} }
)) ),
..
} }
_ => panic!("No match"), ))
}
} }
#[test] #[test]
@ -433,27 +401,24 @@ mod range {
assert!(err.is_none()); assert!(err.is_none());
assert!(block.len() == 1); assert!(block.len() == 1);
match &block[0] {
Statement::Pipeline(Pipeline { expressions }) => { let expressions = &block[0];
assert!(expressions.len() == 1); assert!(expressions.len() == 1);
assert!(matches!( assert!(matches!(
expressions[0], expressions[0],
Expression { Expression {
expr: Expr::Range( expr: Expr::Range(
Some(_), Some(_),
None, None,
None, None,
RangeOperator { RangeOperator {
inclusion: RangeInclusion::Inclusive, inclusion: RangeInclusion::Inclusive,
..
}
),
.. ..
} }
)) ),
..
} }
_ => panic!("No match"), ))
}
} }
#[test] #[test]
@ -465,27 +430,24 @@ mod range {
assert!(err.is_none()); assert!(err.is_none());
assert!(block.len() == 1); assert!(block.len() == 1);
match &block[0] {
Statement::Pipeline(Pipeline { expressions }) => { let expressions = &block[0];
assert!(expressions.len() == 1); assert!(expressions.len() == 1);
assert!(matches!( assert!(matches!(
expressions[0], expressions[0],
Expression { Expression {
expr: Expr::Range( expr: Expr::Range(
None, None,
None, None,
Some(_), Some(_),
RangeOperator { RangeOperator {
inclusion: RangeInclusion::Inclusive, inclusion: RangeInclusion::Inclusive,
..
}
),
.. ..
} }
)) ),
..
} }
_ => panic!("No match"), ))
}
} }
#[test] #[test]
@ -497,27 +459,24 @@ mod range {
assert!(err.is_none()); assert!(err.is_none());
assert!(block.len() == 1); assert!(block.len() == 1);
match &block[0] {
Statement::Pipeline(Pipeline { expressions }) => { let expressions = &block[0];
assert!(expressions.len() == 1); assert!(expressions.len() == 1);
assert!(matches!( assert!(matches!(
expressions[0], expressions[0],
Expression { Expression {
expr: Expr::Range( expr: Expr::Range(
Some(_), Some(_),
None, None,
Some(_), Some(_),
RangeOperator { RangeOperator {
inclusion: RangeInclusion::Inclusive, inclusion: RangeInclusion::Inclusive,
..
}
),
.. ..
} }
)) ),
..
} }
_ => panic!("No match"), ))
}
} }
#[test] #[test]
@ -529,27 +488,24 @@ mod range {
assert!(err.is_none()); assert!(err.is_none());
assert!(block.len() == 1); assert!(block.len() == 1);
match &block[0] {
Statement::Pipeline(Pipeline { expressions }) => { let expressions = &block[0];
assert!(expressions.len() == 1); assert!(expressions.len() == 1);
assert!(matches!( assert!(matches!(
expressions[0], expressions[0],
Expression { Expression {
expr: Expr::Range( expr: Expr::Range(
Some(_), Some(_),
Some(_), Some(_),
Some(_), Some(_),
RangeOperator { RangeOperator {
inclusion: RangeInclusion::Inclusive, inclusion: RangeInclusion::Inclusive,
..
}
),
.. ..
} }
)) ),
..
} }
_ => panic!("No match"), ))
}
} }
#[test] #[test]

View file

@ -2,12 +2,12 @@ use std::ops::{Index, IndexMut};
use crate::{Signature, Span, VarId}; use crate::{Signature, Span, VarId};
use super::Statement; use super::Pipeline;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Block { pub struct Block {
pub signature: Box<Signature>, pub signature: Box<Signature>,
pub stmts: Vec<Statement>, pub pipelines: Vec<Pipeline>,
pub captures: Vec<VarId>, pub captures: Vec<VarId>,
pub redirect_env: bool, pub redirect_env: bool,
pub span: Option<Span>, // None option encodes no span to avoid using test_span() pub span: Option<Span>, // None option encodes no span to avoid using test_span()
@ -15,25 +15,25 @@ pub struct Block {
impl Block { impl Block {
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.stmts.len() self.pipelines.len()
} }
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.stmts.is_empty() self.pipelines.is_empty()
} }
} }
impl Index<usize> for Block { impl Index<usize> for Block {
type Output = Statement; type Output = Pipeline;
fn index(&self, index: usize) -> &Self::Output { fn index(&self, index: usize) -> &Self::Output {
&self.stmts[index] &self.pipelines[index]
} }
} }
impl IndexMut<usize> for Block { impl IndexMut<usize> for Block {
fn index_mut(&mut self, index: usize) -> &mut Self::Output { 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 { pub fn new() -> Self {
Self { Self {
signature: Box::new(Signature::new("")), signature: Box::new(Signature::new("")),
stmts: vec![], pipelines: vec![],
captures: vec![], captures: vec![],
redirect_env: false, redirect_env: false,
span: None, span: None,
@ -57,12 +57,12 @@ impl Block {
impl<T> From<T> for Block impl<T> From<T> for Block
where where
T: Iterator<Item = Statement>, T: Iterator<Item = Pipeline>,
{ {
fn from(stmts: T) -> Self { fn from(pipelines: T) -> Self {
Self { Self {
signature: Box::new(Signature::new("")), signature: Box::new(Signature::new("")),
stmts: stmts.collect(), pipelines: pipelines.collect(),
captures: vec![], captures: vec![],
redirect_env: false, redirect_env: false,
span: None, span: None,

View file

@ -1,4 +1,4 @@
use super::{Expr, Operator, Statement}; use super::{Expr, Operator};
use crate::ast::ImportPattern; use crate::ast::ImportPattern;
use crate::{engine::StateWorkingSet, BlockId, Signature, Span, Type, VarId, IN_VARIABLE_ID}; use crate::{engine::StateWorkingSet, BlockId, Signature, Span, Type, VarId, IN_VARIABLE_ID};
@ -116,7 +116,7 @@ impl Expression {
return true; 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) { match pipeline.expressions.get(0) {
Some(expr) => expr.has_in_variable(working_set), Some(expr) => expr.has_in_variable(working_set),
None => false, None => false,
@ -218,7 +218,7 @@ impl Expression {
Expr::RowCondition(block_id) | Expr::Subexpression(block_id) => { Expr::RowCondition(block_id) | Expr::Subexpression(block_id) => {
let block = working_set.get_block(*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) { if let Some(expr) = pipeline.expressions.get(0) {
expr.has_in_variable(working_set) expr.has_in_variable(working_set)
} else { } else {
@ -261,7 +261,7 @@ impl Expression {
Expr::Block(block_id) => { Expr::Block(block_id) => {
let block = working_set.get_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) { if let Some(expr) = pipeline.expressions.get(0) {
let mut new_expr = expr.clone(); let mut new_expr = expr.clone();
new_expr.replace_in_variable(working_set, new_var_id); 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); let block = working_set.get_block_mut(*block_id);
if let Some(new_expr) = new_expr { 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) { if let Some(expr) = pipeline.expressions.get_mut(0) {
*expr = new_expr *expr = new_expr
} }
@ -353,7 +353,7 @@ impl Expression {
Expr::RowCondition(block_id) | Expr::Subexpression(block_id) => { Expr::RowCondition(block_id) | Expr::Subexpression(block_id) => {
let block = working_set.get_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) { if let Some(expr) = pipeline.expressions.get(0) {
let mut new_expr = expr.clone(); let mut new_expr = expr.clone();
new_expr.replace_in_variable(working_set, new_var_id); 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); let block = working_set.get_block_mut(*block_id);
if let Some(new_expr) = new_expr { 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) { if let Some(expr) = pipeline.expressions.get_mut(0) {
*expr = new_expr *expr = new_expr
} }
@ -420,11 +420,9 @@ impl Expression {
Expr::Block(block_id) => { Expr::Block(block_id) => {
let mut block = working_set.get_block(*block_id).clone(); let mut block = working_set.get_block(*block_id).clone();
for stmt in block.stmts.iter_mut() { for pipeline in block.pipelines.iter_mut() {
if let Statement::Pipeline(pipeline) = stmt { for expr in pipeline.expressions.iter_mut() {
for expr in pipeline.expressions.iter_mut() { expr.replace_span(working_set, replaced, new_span)
expr.replace_span(working_set, replaced, new_span)
}
} }
} }
@ -497,11 +495,9 @@ impl Expression {
Expr::RowCondition(block_id) | Expr::Subexpression(block_id) => { Expr::RowCondition(block_id) | Expr::Subexpression(block_id) => {
let mut block = working_set.get_block(*block_id).clone(); let mut block = working_set.get_block(*block_id).clone();
for stmt in block.stmts.iter_mut() { for pipeline in block.pipelines.iter_mut() {
if let Statement::Pipeline(pipeline) = stmt { for expr in pipeline.expressions.iter_mut() {
for expr in pipeline.expressions.iter_mut() { expr.replace_span(working_set, replaced, new_span)
expr.replace_span(working_set, replaced, new_span)
}
} }
} }

View file

@ -6,7 +6,6 @@ mod expression;
mod import_pattern; mod import_pattern;
mod operator; mod operator;
mod pipeline; mod pipeline;
mod statement;
pub use block::*; pub use block::*;
pub use call::*; pub use call::*;
@ -16,4 +15,3 @@ pub use expression::*;
pub use import_pattern::*; pub use import_pattern::*;
pub use operator::*; pub use operator::*;
pub use pipeline::*; pub use pipeline::*;
pub use statement::*;

View file

@ -1,3 +1,5 @@
use std::ops::{Index, IndexMut};
use crate::ast::Expression; use crate::ast::Expression;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -21,4 +23,26 @@ impl Pipeline {
pub fn from_vec(expressions: Vec<Expression>) -> Pipeline { pub fn from_vec(expressions: Vec<Expression>) -> Pipeline {
Self { expressions } Self { expressions }
} }
pub fn len(&self) -> usize {
self.expressions.len()
}
pub fn is_empty(&self) -> bool {
self.expressions.is_empty()
}
}
impl Index<usize> for Pipeline {
type Output = Expression;
fn index(&self, index: usize) -> &Self::Output {
&self.expressions[index]
}
}
impl IndexMut<usize> for Pipeline {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
&mut self.expressions[index]
}
} }

View file

@ -1,8 +0,0 @@
use super::Pipeline;
use crate::DeclId;
#[derive(Debug, Clone)]
pub enum Statement {
Declaration(DeclId),
Pipeline(Pipeline),
}

View file

@ -17,7 +17,7 @@ use nu_command::{create_default_context, BufferedReader};
use nu_engine::{get_full_help, CallExt}; use nu_engine::{get_full_help, CallExt};
use nu_parser::parse; use nu_parser::parse;
use nu_protocol::{ use nu_protocol::{
ast::{Call, Expr, Expression, Pipeline, Statement}, ast::{Call, Expr, Expression},
engine::{Command, EngineState, Stack, StateWorkingSet}, engine::{Command, EngineState, Stack, StateWorkingSet},
Category, Example, IntoPipelineData, PipelineData, RawStream, ShellError, Signature, Span, Category, Example, IntoPipelineData, PipelineData, RawStream, ShellError, Signature, Span,
Spanned, SyntaxShape, Value, CONFIG_VARIABLE_ID, Spanned, SyntaxShape, Value, CONFIG_VARIABLE_ID,
@ -241,11 +241,11 @@ fn parse_commandline_args(
); );
// We should have a successful parse now // 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 { if let Some(Expression {
expr: Expr::Call(call), expr: Expr::Call(call),
.. ..
}) = expressions.get(0) }) = pipeline.expressions.get(0)
{ {
let redirect_stdin = call.get_named_arg("stdin"); let redirect_stdin = call.get_named_arg("stdin");
let login_shell = call.get_named_arg("login"); let login_shell = call.get_named_arg("login");