mirror of
https://github.com/nushell/nushell.git
synced 2025-03-13 15:08:43 +01:00
Merge 0736ea995a
into 95dcb2fd6c
This commit is contained in:
commit
6e6da88422
@ -11,8 +11,14 @@ fn quickcheck_parse(data: String) -> bool {
|
|||||||
let mut working_set = StateWorkingSet::new(&context);
|
let mut working_set = StateWorkingSet::new(&context);
|
||||||
let _ = working_set.add_file("quickcheck".into(), data.as_bytes());
|
let _ = working_set.add_file("quickcheck".into(), data.as_bytes());
|
||||||
|
|
||||||
let _ =
|
let _ = nu_parser::parse_block(
|
||||||
nu_parser::parse_block(&mut working_set, &tokens, Span::new(0, 0), false, false);
|
&mut working_set,
|
||||||
|
&tokens,
|
||||||
|
Span::new(0, 0),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
|
@ -23,7 +23,7 @@ fn catch_can_access_error() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn catch_can_access_error_as_dollar_in() {
|
fn catch_can_access_error_as_dollar_in() {
|
||||||
let output = nu!("try { foobarbaz } catch { $in | get raw }");
|
let output = nu!("try { foobarbaz } catch { get raw }");
|
||||||
|
|
||||||
assert!(output.err.contains("External command failed"));
|
assert!(output.err.contains("External command failed"));
|
||||||
}
|
}
|
||||||
|
@ -3339,7 +3339,8 @@ pub fn parse_let(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipeline
|
|||||||
}
|
}
|
||||||
|
|
||||||
let rvalue_span = Span::concat(&spans[(span.0 + 1)..]);
|
let rvalue_span = Span::concat(&spans[(span.0 + 1)..]);
|
||||||
let rvalue_block = parse_block(working_set, &tokens, rvalue_span, false, true);
|
let rvalue_block =
|
||||||
|
parse_block(working_set, &tokens, rvalue_span, false, true, false);
|
||||||
|
|
||||||
let output_type = rvalue_block.output_type();
|
let output_type = rvalue_block.output_type();
|
||||||
|
|
||||||
@ -3459,7 +3460,7 @@ pub fn parse_const(working_set: &mut StateWorkingSet, spans: &[Span]) -> (Pipeli
|
|||||||
|
|
||||||
trace!("parsing: const right-hand side subexpression");
|
trace!("parsing: const right-hand side subexpression");
|
||||||
let rvalue_block =
|
let rvalue_block =
|
||||||
parse_block(working_set, &rvalue_tokens, rvalue_span, false, true);
|
parse_block(working_set, &rvalue_tokens, rvalue_span, false, true, false);
|
||||||
let rvalue_ty = rvalue_block.output_type();
|
let rvalue_ty = rvalue_block.output_type();
|
||||||
let rvalue_block_id = working_set.add_block(Arc::new(rvalue_block));
|
let rvalue_block_id = working_set.add_block(Arc::new(rvalue_block));
|
||||||
let rvalue = Expression::new(
|
let rvalue = Expression::new(
|
||||||
@ -3621,7 +3622,8 @@ pub fn parse_mut(working_set: &mut StateWorkingSet, spans: &[Span]) -> Pipeline
|
|||||||
}
|
}
|
||||||
|
|
||||||
let rvalue_span = Span::concat(&spans[(span.0 + 1)..]);
|
let rvalue_span = Span::concat(&spans[(span.0 + 1)..]);
|
||||||
let rvalue_block = parse_block(working_set, &tokens, rvalue_span, false, true);
|
let rvalue_block =
|
||||||
|
parse_block(working_set, &tokens, rvalue_span, false, true, false);
|
||||||
|
|
||||||
let output_type = rvalue_block.output_type();
|
let output_type = rvalue_block.output_type();
|
||||||
|
|
||||||
|
@ -14,8 +14,8 @@ use log::trace;
|
|||||||
use nu_engine::DIR_VAR_PARSER_INFO;
|
use nu_engine::DIR_VAR_PARSER_INFO;
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::*, engine::StateWorkingSet, eval_const::eval_constant, BlockId, DeclId, DidYouMean,
|
ast::*, engine::StateWorkingSet, eval_const::eval_constant, BlockId, DeclId, DidYouMean,
|
||||||
FilesizeUnit, Flag, ParseError, PositionalArg, ShellError, Signature, Span, Spanned,
|
FilesizeUnit, Flag, ParseError, ParseWarning, PositionalArg, ShellError, Signature, Span,
|
||||||
SyntaxShape, Type, Value, VarId, ENV_VARIABLE_ID, IN_VARIABLE_ID,
|
Spanned, SyntaxShape, Type, Value, VarId, ENV_VARIABLE_ID, IN_VARIABLE_ID,
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
@ -2452,7 +2452,7 @@ pub fn parse_full_cell_path(
|
|||||||
|
|
||||||
// Creating a Type scope to parse the new block. This will keep track of
|
// Creating a Type scope to parse the new block. This will keep track of
|
||||||
// the previous input type found in that block
|
// the previous input type found in that block
|
||||||
let output = parse_block(working_set, &output, span, true, true);
|
let output = parse_block(working_set, &output, span, true, true, false);
|
||||||
|
|
||||||
let ty = output.output_type();
|
let ty = output.output_type();
|
||||||
|
|
||||||
@ -4596,7 +4596,14 @@ pub fn parse_block_expression(working_set: &mut StateWorkingSet, span: Span) ->
|
|||||||
_ => (None, 0),
|
_ => (None, 0),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut output = parse_block(working_set, &output[amt_to_skip..], span, false, false);
|
let mut output = parse_block(
|
||||||
|
working_set,
|
||||||
|
&output[amt_to_skip..],
|
||||||
|
span,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
if let Some(signature) = signature {
|
if let Some(signature) = signature {
|
||||||
output.signature = signature.0;
|
output.signature = signature.0;
|
||||||
@ -4915,7 +4922,14 @@ pub fn parse_closure_expression(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut output = parse_block(working_set, &output[amt_to_skip..], span, false, false);
|
let mut output = parse_block(
|
||||||
|
working_set,
|
||||||
|
&output[amt_to_skip..],
|
||||||
|
span,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
if let Some(signature) = signature {
|
if let Some(signature) = signature {
|
||||||
output.signature = signature.0;
|
output.signature = signature.0;
|
||||||
@ -5213,7 +5227,7 @@ pub fn parse_assignment_expression(
|
|||||||
working_set.parse_errors.extend(rhs_error);
|
working_set.parse_errors.extend(rhs_error);
|
||||||
|
|
||||||
trace!("parsing: assignment right-hand side subexpression");
|
trace!("parsing: assignment right-hand side subexpression");
|
||||||
let rhs_block = parse_block(working_set, &rhs_tokens, rhs_span, false, true);
|
let rhs_block = parse_block(working_set, &rhs_tokens, rhs_span, false, true, false);
|
||||||
let rhs_ty = rhs_block.output_type();
|
let rhs_ty = rhs_block.output_type();
|
||||||
|
|
||||||
// TEMP: double-check that if the RHS block starts with an external call, it must start with a
|
// TEMP: double-check that if the RHS block starts with an external call, it must start with a
|
||||||
@ -6305,6 +6319,7 @@ pub fn parse_block(
|
|||||||
span: Span,
|
span: Span,
|
||||||
scoped: bool,
|
scoped: bool,
|
||||||
is_subexpression: bool,
|
is_subexpression: bool,
|
||||||
|
is_closure: bool,
|
||||||
) -> Block {
|
) -> Block {
|
||||||
let (lite_block, err) = lite_parse(tokens, working_set);
|
let (lite_block, err) = lite_parse(tokens, working_set);
|
||||||
if let Some(err) = err {
|
if let Some(err) = err {
|
||||||
@ -6342,6 +6357,10 @@ pub fn parse_block(
|
|||||||
.flat_map(|pipeline| pipeline.elements.first())
|
.flat_map(|pipeline| pipeline.elements.first())
|
||||||
.any(|element| element.has_in_variable(working_set))
|
.any(|element| element.has_in_variable(working_set))
|
||||||
{
|
{
|
||||||
|
if is_closure {
|
||||||
|
check_block_pipes_in(working_set, &block);
|
||||||
|
}
|
||||||
|
|
||||||
// Move the block out to prepare it to become a subexpression
|
// Move the block out to prepare it to become a subexpression
|
||||||
let inner_block = std::mem::take(&mut block);
|
let inner_block = std::mem::take(&mut block);
|
||||||
block.span = inner_block.span;
|
block.span = inner_block.span;
|
||||||
@ -6851,6 +6870,36 @@ fn wrap_expr_with_collect(working_set: &mut StateWorkingSet, expr: Expression) -
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Report a warning if the first pipeline element of a block is `$in` followed by a pipe
|
||||||
|
fn check_block_pipes_in(working_set: &mut StateWorkingSet, block: &Block) {
|
||||||
|
if let Some(elements) = block.pipelines.first().map(|pipeline| &pipeline.elements) {
|
||||||
|
// only warn if we're also piping into something
|
||||||
|
let element = match elements.len() {
|
||||||
|
..2 => return,
|
||||||
|
2.. => elements.first().expect("at least two elements"),
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Expr::FullCellPath(cell_path) = &element.expr.expr {
|
||||||
|
if matches!(
|
||||||
|
**cell_path,
|
||||||
|
FullCellPath {
|
||||||
|
head: Expression {
|
||||||
|
expr: Expr::Var(id),
|
||||||
|
..
|
||||||
|
},
|
||||||
|
..
|
||||||
|
} if id == IN_VARIABLE_ID
|
||||||
|
) {
|
||||||
|
working_set
|
||||||
|
.parse_warnings
|
||||||
|
.push(ParseWarning::UnnecessaryInVariable {
|
||||||
|
span: element.expr.span(working_set),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Parses a vector of u8 to create an AST Block. If a file name is given, then
|
// Parses a vector of u8 to create an AST Block. If a file name is given, then
|
||||||
// the name is stored in the working set. When parsing a source without a file
|
// the name is stored in the working set. When parsing a source without a file
|
||||||
// name, the source of bytes is stored as "source"
|
// name, the source of bytes is stored as "source"
|
||||||
@ -6889,7 +6938,14 @@ pub fn parse(
|
|||||||
working_set.error(err)
|
working_set.error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
Arc::new(parse_block(working_set, &output, new_span, scoped, false))
|
Arc::new(parse_block(
|
||||||
|
working_set,
|
||||||
|
&output,
|
||||||
|
new_span,
|
||||||
|
scoped,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1132,6 +1132,21 @@ impl<'a> GetSpan for &'a StateWorkingSet<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl GetSpan for StateWorkingSet<'_> {
|
||||||
|
fn get_span(&self, span_id: SpanId) -> Span {
|
||||||
|
let num_permanent_spans = self.permanent_state.num_spans();
|
||||||
|
if span_id.get() < num_permanent_spans {
|
||||||
|
self.permanent_state.get_span(span_id)
|
||||||
|
} else {
|
||||||
|
*self
|
||||||
|
.delta
|
||||||
|
.spans
|
||||||
|
.get(span_id.get() - num_permanent_spans)
|
||||||
|
.expect("internal error: missing span")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl miette::SourceCode for &StateWorkingSet<'_> {
|
impl miette::SourceCode for &StateWorkingSet<'_> {
|
||||||
fn read_span<'b>(
|
fn read_span<'b>(
|
||||||
&'b self,
|
&'b self,
|
||||||
|
@ -14,12 +14,20 @@ pub enum ParseWarning {
|
|||||||
span: Span,
|
span: Span,
|
||||||
url: String,
|
url: String,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
#[error("Found $in at the start of a command.")]
|
||||||
|
#[diagnostic(help("Using $in at the start of a command collects the pipeline input.\nIf you did mean to collect the pipeline input, replace this with the `collect` command."))]
|
||||||
|
UnnecessaryInVariable {
|
||||||
|
#[label("try removing this")]
|
||||||
|
span: Span,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParseWarning {
|
impl ParseWarning {
|
||||||
pub fn span(&self) -> Span {
|
pub fn span(&self) -> Span {
|
||||||
match self {
|
match self {
|
||||||
ParseWarning::DeprecatedWarning { span, .. } => *span,
|
ParseWarning::DeprecatedWarning { span, .. } => *span,
|
||||||
|
ParseWarning::UnnecessaryInVariable { span, .. } => *span,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ def format-event [ ] {
|
|||||||
# Replace numeric value of raw_code with hex string
|
# Replace numeric value of raw_code with hex string
|
||||||
let record = match $record {
|
let record = match $record {
|
||||||
{raw_code: $code} => {
|
{raw_code: $code} => {
|
||||||
$record | update raw_code {|| $in | format number | get upperhex}
|
$record | update raw_code {|| format number | get upperhex}
|
||||||
}
|
}
|
||||||
_ => $record
|
_ => $record
|
||||||
}
|
}
|
||||||
@ -12,7 +12,7 @@ def format-event [ ] {
|
|||||||
# Replace numeric value of raw_modifiers with binary string
|
# Replace numeric value of raw_modifiers with binary string
|
||||||
let record = match $record {
|
let record = match $record {
|
||||||
{raw_modifiers: $flags} => {
|
{raw_modifiers: $flags} => {
|
||||||
$record | update raw_modifiers {|| $in | format number | get binary}
|
$record | update raw_modifiers {|| format number | get binary}
|
||||||
}
|
}
|
||||||
_ => $record
|
_ => $record
|
||||||
}
|
}
|
||||||
|
@ -95,7 +95,7 @@ def xupdate-string-step [ step: string rest: list updater: closure ] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def xupdate-int-step [ step: int rest: list updater: closure ] {
|
def xupdate-int-step [ step: int rest: list updater: closure ] {
|
||||||
$in | enumerate | each {|it|
|
enumerate | each {|it|
|
||||||
let item = $it.item
|
let item = $it.item
|
||||||
let idx = $it.index
|
let idx = $it.index
|
||||||
|
|
||||||
@ -108,7 +108,7 @@ def xupdate-int-step [ step: int rest: list updater: closure ] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def xupdate-closure-step [ step: closure rest: list updater: closure ] {
|
def xupdate-closure-step [ step: closure rest: list updater: closure ] {
|
||||||
$in | each {|it|
|
each {|it|
|
||||||
if (do $step $it) {
|
if (do $step $it) {
|
||||||
[ $it ] | xupdate-internal $rest $updater | get 0
|
[ $it ] | xupdate-internal $rest $updater | get 0
|
||||||
} else {
|
} else {
|
||||||
@ -194,7 +194,7 @@ export def xinsert [
|
|||||||
# position is greater than number of elements) in content of all entries of input matched by
|
# position is greater than number of elements) in content of all entries of input matched by
|
||||||
# path. If not specified inserts at the end.
|
# path. If not specified inserts at the end.
|
||||||
] {
|
] {
|
||||||
$in | xupdate $path {|entry|
|
xupdate $path {|entry|
|
||||||
match ($entry | xtype) {
|
match ($entry | xtype) {
|
||||||
'tag' => {
|
'tag' => {
|
||||||
let new_content = if $position == null {
|
let new_content = if $position == null {
|
||||||
|
Loading…
Reference in New Issue
Block a user