Add an alias denylist for expansions (#4871)

This commit is contained in:
JT 2022-03-19 08:03:57 +13:00 committed by GitHub
parent 5a1af4d661
commit 983d115bc0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 516 additions and 159 deletions

View File

@ -31,7 +31,7 @@ pub fn evaluate_commands(
(commands.item.as_bytes(), commands.span.start)
};
let (output, err) = parse(&mut working_set, None, input, false);
let (output, err) = parse(&mut working_set, None, input, false, &[]);
if let Some(err) = err {
report_error(&working_set, &err);

View File

@ -206,7 +206,13 @@ impl NuCompleter {
let mut line = line.to_string();
line.insert(pos, 'a');
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 pipeline in output.pipelines.into_iter() {
for expr in pipeline.expressions {

View File

@ -36,7 +36,7 @@ pub fn evaluate_file(
let mut working_set = StateWorkingSet::new(engine_state);
trace!("parsing file: {}", path);
let _ = parse(&mut working_set, Some(&path), &file, false);
let _ = parse(&mut working_set, Some(&path), &file, false, &[]);
if working_set.find_decl(b"main").is_some() {
let args = format!("main {}", args.join(" "));

View File

@ -104,7 +104,7 @@ fn get_prompt_string(
}
Value::String { val: source, .. } => {
let mut working_set = StateWorkingSet::new(engine_state);
let (block, _) = parse(&mut working_set, None, source.as_bytes(), true);
let (block, _) = parse(&mut working_set, None, source.as_bytes(), true, &[]);
// Use eval_subexpression to force a redirection of output, so we can use everything in prompt
let ret_val = eval_subexpression(
engine_state,

View File

@ -17,7 +17,7 @@ impl Highlighter for NuHighlighter {
let (shapes, global_span_offset) = {
let mut working_set = StateWorkingSet::new(&self.engine_state);
let (block, _) = parse(&mut working_set, None, line.as_bytes(), false);
let (block, _) = parse(&mut working_set, None, line.as_bytes(), false, &[]);
let shapes = flatten_block(&working_set, &block);
(shapes, self.engine_state.next_span_start())

View File

@ -287,6 +287,7 @@ pub fn eval_source(
Some(fname), // format!("entry #{}", entry_num)
source,
false,
&[],
);
if let Some(err) = err {
report_error(&working_set, &err);

View File

@ -9,7 +9,7 @@ pub struct NuValidator {
impl Validator for NuValidator {
fn validate(&self, line: &str) -> ValidationResult {
let mut working_set = StateWorkingSet::new(&self.engine_state);
let (_, err) = parse(&mut working_set, None, line.as_bytes(), false);
let (_, err) = parse(&mut working_set, None, line.as_bytes(), false, &[]);
if matches!(err, Some(ParseError::UnexpectedEof(..))) {
ValidationResult::Incomplete

View File

@ -44,7 +44,13 @@ pub fn test_dataframe(cmds: Vec<Box<dyn Command + 'static>>) {
let (block, delta) = {
let mut working_set = StateWorkingSet::new(&*engine_state);
let (output, err) = parse(&mut working_set, None, example.example.as_bytes(), false);
let (output, err) = parse(
&mut working_set,
None,
example.example.as_bytes(),
false,
&[],
);
if let Some(err) = err {
panic!("test parse error in `{}`: {:?}", example.example, err)

View File

@ -84,7 +84,13 @@ pub fn test_examples(cmd: impl Command + 'static) {
let (block, delta) = {
let mut working_set = StateWorkingSet::new(&*engine_state);
let (output, err) = parse(&mut working_set, None, example.example.as_bytes(), false);
let (output, err) = parse(
&mut working_set,
None,
example.example.as_bytes(),
false,
&[],
);
if let Some(err) = err {
panic!("test parse error in `{}`: {:?}", example.example, err)

View File

@ -89,7 +89,7 @@ impl Command for FromNuon {
let (lite_block, err) = nu_parser::lite_parse(&lexed);
error = error.or(err);
let (mut block, err) = nu_parser::parse_block(&mut working_set, &lite_block, true);
let (mut block, err) = nu_parser::parse_block(&mut working_set, &lite_block, true, &[]);
error = error.or(err);
if let Some(pipeline) = block.pipelines.get(1) {

View File

@ -19,7 +19,7 @@ fn quickcheck_parse(data: String) -> bool {
let mut working_set = StateWorkingSet::new(&context);
working_set.add_file("quickcheck".into(), data.as_bytes());
let _ = nu_parser::parse_block(&mut working_set, &lite_block, false);
let _ = nu_parser::parse_block(&mut working_set, &lite_block, false, &[]);
}
}
true

View File

@ -51,7 +51,7 @@ impl Command for KnownExternal {
let spans: Vec<_> = lexed.into_iter().map(|x| x.span).collect();
let mut working_set = StateWorkingSet::new(&engine_state);
let (external_call, _) = crate::parse_external_call(&mut working_set, &spans);
let (external_call, _) = crate::parse_external_call(&mut working_set, &spans, &[]);
let delta = working_set.render();
engine_state.merge_delta(delta, None, ".")?;

View File

@ -26,7 +26,11 @@ use crate::{
ParseError,
};
pub fn parse_def_predecl(working_set: &mut StateWorkingSet, spans: &[Span]) -> Option<ParseError> {
pub fn parse_def_predecl(
working_set: &mut StateWorkingSet,
spans: &[Span],
expand_aliases_denylist: &[usize],
) -> Option<ParseError> {
let name = working_set.get_span_contents(spans[0]);
// handle "export def" same as "def"
@ -47,7 +51,7 @@ pub fn parse_def_predecl(working_set: &mut StateWorkingSet, spans: &[Span]) -> O
// The second time is when we actually parse the body itworking_set.
// We can't reuse the first time because the variables that are created during parse_signature
// are lost when we exit the scope below.
let (sig, ..) = parse_signature(working_set, spans[2]);
let (sig, ..) = parse_signature(working_set, spans[2], expand_aliases_denylist);
let signature = sig.as_signature();
working_set.exit_scope();
@ -70,7 +74,7 @@ pub fn parse_def_predecl(working_set: &mut StateWorkingSet, spans: &[Span]) -> O
// The second time is when we actually parse the body itworking_set.
// We can't reuse the first time because the variables that are created during parse_signature
// are lost when we exit the scope below.
let (sig, ..) = parse_signature(working_set, spans[2]);
let (sig, ..) = parse_signature(working_set, spans[2], expand_aliases_denylist);
let signature = sig.as_signature();
working_set.exit_scope();
@ -95,6 +99,7 @@ pub fn parse_def_predecl(working_set: &mut StateWorkingSet, spans: &[Span]) -> O
pub fn parse_for(
working_set: &mut StateWorkingSet,
spans: &[Span],
expand_aliases_denylist: &[usize],
) -> (Expression, Option<ParseError>) {
// Checking that the function is used with the correct name
// Maybe this is not necessary but it is a sanity check
@ -123,7 +128,13 @@ pub fn parse_for(
}
Some(decl_id) => {
working_set.enter_scope();
let (call, mut err) = parse_internal_call(working_set, spans[0], &spans[1..], decl_id);
let (call, mut err) = parse_internal_call(
working_set,
spans[0],
&spans[1..],
decl_id,
expand_aliases_denylist,
);
working_set.exit_scope();
let call_span = span(spans);
@ -251,6 +262,7 @@ fn build_usage(working_set: &StateWorkingSet, spans: &[Span]) -> String {
pub fn parse_def(
working_set: &mut StateWorkingSet,
lite_command: &LiteCommand,
expand_aliases_denylist: &[usize],
) -> (Pipeline, Option<ParseError>) {
let spans = &lite_command.parts[..];
@ -285,7 +297,13 @@ pub fn parse_def(
}
Some(decl_id) => {
working_set.enter_scope();
let (call, mut err) = parse_internal_call(working_set, spans[0], &spans[1..], decl_id);
let (call, mut err) = parse_internal_call(
working_set,
spans[0],
&spans[1..],
decl_id,
expand_aliases_denylist,
);
working_set.exit_scope();
let call_span = span(spans);
@ -385,6 +403,7 @@ pub fn parse_def(
pub fn parse_extern(
working_set: &mut StateWorkingSet,
lite_command: &LiteCommand,
expand_aliases_denylist: &[usize],
) -> (Pipeline, Option<ParseError>) {
let spans = &lite_command.parts[..];
let mut error = None;
@ -420,7 +439,13 @@ pub fn parse_extern(
}
Some(decl_id) => {
working_set.enter_scope();
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,
expand_aliases_denylist,
);
working_set.exit_scope();
error = error.or(err);
@ -486,6 +511,7 @@ pub fn parse_extern(
pub fn parse_alias(
working_set: &mut StateWorkingSet,
spans: &[Span],
expand_aliases_denylist: &[usize],
) -> (Pipeline, Option<ParseError>) {
let name = working_set.get_span_contents(spans[0]);
@ -495,7 +521,13 @@ pub fn parse_alias(
}
if let Some(decl_id) = working_set.find_decl(b"alias") {
let (call, _) = parse_internal_call(working_set, spans[0], &spans[1..], decl_id);
let (call, _) = parse_internal_call(
working_set,
spans[0],
&spans[1..],
decl_id,
expand_aliases_denylist,
);
if spans.len() >= 4 {
let alias_name = working_set.get_span_contents(spans[1]);
@ -539,6 +571,7 @@ pub fn parse_alias(
pub fn parse_export(
working_set: &mut StateWorkingSet,
lite_command: &LiteCommand,
expand_aliases_denylist: &[usize],
) -> (Pipeline, Option<Exportable>, Option<ParseError>) {
let spans = &lite_command.parts[..];
let mut error = None;
@ -597,7 +630,8 @@ pub fn parse_export(
comments: lite_command.comments.clone(),
parts: spans[1..].to_vec(),
};
let (pipeline, err) = parse_def(working_set, &lite_command);
let (pipeline, err) =
parse_def(working_set, &lite_command, expand_aliases_denylist);
error = error.or(err);
let export_def_decl_id = if let Some(id) = working_set.find_decl(b"export def") {
@ -655,7 +689,8 @@ pub fn parse_export(
comments: lite_command.comments.clone(),
parts: spans[1..].to_vec(),
};
let (pipeline, err) = parse_def(working_set, &lite_command);
let (pipeline, err) =
parse_def(working_set, &lite_command, expand_aliases_denylist);
error = error.or(err);
let export_def_decl_id = if let Some(id) = working_set.find_decl(b"export def-env")
@ -738,6 +773,7 @@ pub fn parse_export(
working_set,
&SyntaxShape::Block(None),
*block_span,
expand_aliases_denylist,
);
error = error.or(err);
@ -835,6 +871,7 @@ pub fn parse_export(
pub fn parse_module_block(
working_set: &mut StateWorkingSet,
span: Span,
expand_aliases_denylist: &[usize],
) -> (Block, Overlay, Option<ParseError>) {
let mut error = None;
@ -851,7 +888,11 @@ pub fn parse_module_block(
for pipeline in &output.block {
// TODO: Should we add export env predecls as well?
if pipeline.commands.len() == 1 {
parse_def_predecl(working_set, &pipeline.commands[0].parts);
parse_def_predecl(
working_set,
&pipeline.commands[0].parts,
expand_aliases_denylist,
);
}
}
@ -866,12 +907,17 @@ pub fn parse_module_block(
let (pipeline, err) = match name {
b"def" | b"def-env" => {
let (pipeline, err) = parse_def(working_set, &pipeline.commands[0]);
let (pipeline, err) =
parse_def(working_set, &pipeline.commands[0], expand_aliases_denylist);
(pipeline, err)
}
b"extern" => {
let (pipeline, err) = parse_extern(working_set, &pipeline.commands[0]);
let (pipeline, err) = parse_extern(
working_set,
&pipeline.commands[0],
expand_aliases_denylist,
);
(pipeline, err)
}
@ -884,8 +930,11 @@ 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 (pipe, exportable, err) =
parse_export(working_set, &pipeline.commands[0]);
let (pipe, exportable, err) = parse_export(
working_set,
&pipeline.commands[0],
expand_aliases_denylist,
);
if err.is_none() {
let name_span = pipeline.commands[0].parts[2];
@ -934,6 +983,7 @@ pub fn parse_module_block(
pub fn parse_module(
working_set: &mut StateWorkingSet,
spans: &[Span],
expand_aliases_denylist: &[usize],
) -> (Pipeline, Option<ParseError>) {
// 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.
@ -972,7 +1022,8 @@ pub fn parse_module(
let block_span = Span { start, end };
let (block, overlay, err) = parse_module_block(working_set, block_span);
let (block, overlay, err) =
parse_module_block(working_set, block_span, expand_aliases_denylist);
error = error.or(err);
let block_id = working_set.add_block(block);
@ -1021,6 +1072,7 @@ pub fn parse_module(
pub fn parse_use(
working_set: &mut StateWorkingSet,
spans: &[Span],
expand_aliases_denylist: &[usize],
) -> (Pipeline, Option<ParseError>) {
if working_set.get_span_contents(spans[0]) != b"use" {
return (
@ -1034,7 +1086,13 @@ pub fn parse_use(
let (call, call_span, use_decl_id) = match working_set.find_decl(b"use") {
Some(decl_id) => {
let (call, mut err) = parse_internal_call(working_set, spans[0], &spans[1..], decl_id);
let (call, mut err) = parse_internal_call(
working_set,
spans[0],
&spans[1..],
decl_id,
expand_aliases_denylist,
);
let decl = working_set.get_decl(decl_id);
let call_span = span(spans);
@ -1124,8 +1182,11 @@ pub fn parse_use(
working_set.add_file(module_filename, &contents);
let span_end = working_set.next_span_start();
let (block, overlay, err) =
parse_module_block(working_set, Span::new(span_start, span_end));
let (block, overlay, err) = parse_module_block(
working_set,
Span::new(span_start, span_end),
expand_aliases_denylist,
);
error = error.or(err);
let _ = working_set.add_block(block);
@ -1230,6 +1291,7 @@ pub fn parse_use(
pub fn parse_hide(
working_set: &mut StateWorkingSet,
spans: &[Span],
expand_aliases_denylist: &[usize],
) -> (Pipeline, Option<ParseError>) {
if working_set.get_span_contents(spans[0]) != b"hide" {
return (
@ -1243,7 +1305,13 @@ pub fn parse_hide(
let (call, call_span, hide_decl_id) = match working_set.find_decl(b"hide") {
Some(decl_id) => {
let (call, mut err) = parse_internal_call(working_set, spans[0], &spans[1..], decl_id);
let (call, mut err) = parse_internal_call(
working_set,
spans[0],
&spans[1..],
decl_id,
expand_aliases_denylist,
);
let decl = working_set.get_decl(decl_id);
let call_span = span(spans);
@ -1440,6 +1508,7 @@ pub fn parse_hide(
pub fn parse_let(
working_set: &mut StateWorkingSet,
spans: &[Span],
expand_aliases_denylist: &[usize],
) -> (Pipeline, Option<ParseError>) {
let name = working_set.get_span_contents(spans[0]);
@ -1466,6 +1535,7 @@ pub fn parse_let(
spans,
&mut idx,
&SyntaxShape::Keyword(b"=".to_vec(), Box::new(SyntaxShape::Expression)),
expand_aliases_denylist,
);
error = error.or(err);
@ -1512,7 +1582,13 @@ 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,
expand_aliases_denylist,
);
return (
Pipeline {
@ -1539,6 +1615,7 @@ pub fn parse_let(
pub fn parse_source(
working_set: &mut StateWorkingSet,
spans: &[Span],
expand_aliases_denylist: &[usize],
) -> (Pipeline, Option<ParseError>) {
let mut error = None;
let name = working_set.get_span_contents(spans[0]);
@ -1548,7 +1625,13 @@ pub fn parse_source(
let cwd = working_set.get_cwd();
// Is this the right call to be using here?
// Some of the others (`parse_let`) use it, some of them (`parse_hide`) don't.
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,
expand_aliases_denylist,
);
error = error.or(err);
if error.is_some() || call.has_flag("help") {
@ -1577,6 +1660,7 @@ pub fn parse_source(
path.file_name().and_then(|x| x.to_str()),
&contents,
false,
expand_aliases_denylist,
);
if err.is_some() {
@ -1648,6 +1732,7 @@ pub fn parse_source(
pub fn parse_register(
working_set: &mut StateWorkingSet,
spans: &[Span],
expand_aliases_denylist: &[usize],
) -> (Pipeline, Option<ParseError>) {
use nu_plugin::{get_signature, EncodingType, PluginDeclaration};
use nu_protocol::Signature;
@ -1679,7 +1764,13 @@ pub fn parse_register(
)
}
Some(decl_id) => {
let (call, mut err) = parse_internal_call(working_set, spans[0], &spans[1..], decl_id);
let (call, mut err) = parse_internal_call(
working_set,
spans[0],
&spans[1..],
decl_id,
expand_aliases_denylist,
);
let decl = working_set.get_decl(decl_id);
let call_span = span(spans);

View File

@ -208,6 +208,7 @@ pub fn check_name<'a>(
pub fn parse_external_call(
working_set: &mut StateWorkingSet,
spans: &[Span],
expand_aliases_denylist: &[usize],
) -> (Expression, Option<ParseError>) {
let mut args = vec![];
@ -235,10 +236,17 @@ pub fn parse_external_call(
new_spans.extend(&spans[1..])
}
working_set.enter_scope();
working_set.hide_alias(&head_contents);
let (mut result, err) = parse_external_call(working_set, &new_spans);
working_set.exit_scope();
let expand_aliases_denylist = if let Some(alias_id) = working_set.find_alias(&head_contents)
{
let mut expand_aliases_denylist = expand_aliases_denylist.to_vec();
expand_aliases_denylist.push(alias_id);
expand_aliases_denylist
} else {
expand_aliases_denylist.to_vec()
};
let (mut result, err) =
parse_external_call(working_set, &new_spans, &expand_aliases_denylist);
result.replace_span(working_set, expansion_span, orig_span);
return (result, err);
@ -247,7 +255,7 @@ pub fn parse_external_call(
let mut error = None;
let head = if head_contents.starts_with(b"$") || head_contents.starts_with(b"(") {
let (arg, err) = parse_expression(working_set, &[head_span], true);
let (arg, err) = parse_expression(working_set, &[head_span], expand_aliases_denylist);
error = error.or(err);
Box::new(arg)
} else {
@ -263,11 +271,12 @@ pub fn parse_external_call(
let contents = working_set.get_span_contents(*span);
if contents.starts_with(b"$") || contents.starts_with(b"(") {
let (arg, err) = parse_dollar_expr(working_set, *span);
let (arg, err) = parse_dollar_expr(working_set, *span, expand_aliases_denylist);
error = error.or(err);
args.push(arg);
} else if contents.starts_with(b"(") {
let (arg, err) = parse_full_cell_path(working_set, None, *span);
let (arg, err) =
parse_full_cell_path(working_set, None, *span, expand_aliases_denylist);
error = error.or(err);
args.push(arg);
} else {
@ -295,6 +304,7 @@ fn parse_long_flag(
spans: &[Span],
spans_idx: &mut usize,
sig: &Signature,
expand_aliases_denylist: &[usize],
) -> (
Option<Spanned<String>>,
Option<Expression>,
@ -317,7 +327,8 @@ fn parse_long_flag(
let mut span = arg_span;
span.start += long_name_len + 3; //offset by long flag and '='
let (arg, err) = parse_value(working_set, span, arg_shape);
let (arg, err) =
parse_value(working_set, span, arg_shape, expand_aliases_denylist);
(
Some(Spanned {
@ -331,7 +342,8 @@ fn parse_long_flag(
err,
)
} else if let Some(arg) = spans.get(*spans_idx + 1) {
let (arg, err) = parse_value(working_set, *arg, arg_shape);
let (arg, err) =
parse_value(working_set, *arg, arg_shape, expand_aliases_denylist);
*spans_idx += 1;
(
@ -554,6 +566,7 @@ pub fn parse_multispan_value(
spans: &[Span],
spans_idx: &mut usize,
shape: &SyntaxShape,
expand_aliases_denylist: &[usize],
) -> (Expression, Option<ParseError>) {
let mut error = None;
@ -568,7 +581,8 @@ pub fn parse_multispan_value(
}
SyntaxShape::RowCondition => {
trace!("parsing: row condition");
let (arg, err) = parse_row_condition(working_set, &spans[*spans_idx..]);
let (arg, err) =
parse_row_condition(working_set, &spans[*spans_idx..], expand_aliases_denylist);
error = error.or(err);
*spans_idx = spans.len() - 1;
@ -577,7 +591,12 @@ pub fn parse_multispan_value(
SyntaxShape::MathExpression => {
trace!("parsing: math expression");
let (arg, err) = parse_math_expression(working_set, &spans[*spans_idx..], None);
let (arg, err) = parse_math_expression(
working_set,
&spans[*spans_idx..],
None,
expand_aliases_denylist,
);
error = error.or(err);
*spans_idx = spans.len() - 1;
@ -586,7 +605,8 @@ pub fn parse_multispan_value(
SyntaxShape::Expression => {
trace!("parsing: expression");
let (arg, err) = parse_expression(working_set, &spans[*spans_idx..], true);
let (arg, err) =
parse_expression(working_set, &spans[*spans_idx..], expand_aliases_denylist);
error = error.or(err);
*spans_idx = spans.len() - 1;
@ -595,7 +615,8 @@ pub fn parse_multispan_value(
SyntaxShape::ImportPattern => {
trace!("parsing: import pattern");
let (arg, err) = parse_import_pattern(working_set, &spans[*spans_idx..]);
let (arg, err) =
parse_import_pattern(working_set, &spans[*spans_idx..], expand_aliases_denylist);
error = error.or(err);
*spans_idx = spans.len() - 1;
@ -649,7 +670,8 @@ pub fn parse_multispan_value(
);
}
let keyword_span = spans[*spans_idx - 1];
let (expr, err) = parse_multispan_value(working_set, spans, spans_idx, arg);
let (expr, err) =
parse_multispan_value(working_set, spans, spans_idx, arg, expand_aliases_denylist);
error = error.or(err);
let ty = expr.ty.clone();
@ -667,7 +689,7 @@ pub fn parse_multispan_value(
// All other cases are single-span values
let arg_span = spans[*spans_idx];
let (arg, err) = parse_value(working_set, arg_span, shape);
let (arg, err) = parse_value(working_set, arg_span, shape, expand_aliases_denylist);
error = error.or(err);
(arg, error)
@ -680,6 +702,7 @@ pub fn parse_internal_call(
command_span: Span,
spans: &[Span],
decl_id: usize,
expand_aliases_denylist: &[usize],
) -> (Box<Call>, Option<ParseError>) {
trace!("parsing: internal call (decl id: {})", decl_id);
@ -706,7 +729,13 @@ pub fn parse_internal_call(
let arg_span = spans[spans_idx];
// Check if we're on a long flag, if so, parse
let (long_name, arg, err) = parse_long_flag(working_set, spans, &mut spans_idx, &signature);
let (long_name, arg, err) = parse_long_flag(
working_set,
spans,
&mut spans_idx,
&signature,
expand_aliases_denylist,
);
if let Some(long_name) = long_name {
// We found a long flag, like --bar
error = error.or(err);
@ -729,7 +758,8 @@ pub fn parse_internal_call(
for flag in short_flags {
if let Some(arg_shape) = flag.arg {
if let Some(arg) = spans.get(spans_idx + 1) {
let (arg, err) = parse_value(working_set, *arg, &arg_shape);
let (arg, err) =
parse_value(working_set, *arg, &arg_shape, expand_aliases_denylist);
error = error.or(err);
call.named.push((
@ -793,6 +823,7 @@ pub fn parse_internal_call(
&spans[..end],
&mut spans_idx,
&positional.shape,
expand_aliases_denylist,
);
error = error.or(err);
@ -839,8 +870,8 @@ pub fn parse_internal_call(
pub fn parse_call(
working_set: &mut StateWorkingSet,
spans: &[Span],
expand_aliases: bool,
head: Span,
expand_aliases_denylist: &[usize],
) -> (Expression, Option<ParseError>) {
trace!("parsing: call");
@ -883,9 +914,9 @@ pub fn parse_call(
name.extend(name_part);
}
if expand_aliases {
// If the word is an alias, expand it and re-parse the expression
if let Some(alias_id) = working_set.find_alias(&name) {
// If the word is an alias, expand it and re-parse the expression
if let Some(alias_id) = working_set.find_alias(&name) {
if !expand_aliases_denylist.contains(&alias_id) {
trace!("expanding alias");
let expansion = working_set.get_alias(alias_id);
@ -901,17 +932,15 @@ pub fn parse_call(
new_spans.extend(&spans[(pos + 1)..]);
}
let alias_id = working_set.hide_alias(&name);
let mut expand_aliases_denylist = expand_aliases_denylist.to_vec();
expand_aliases_denylist.push(alias_id);
let lite_command = LiteCommand {
comments: vec![],
parts: new_spans.clone(),
};
let (mut result, err) = parse_builtin_commands(working_set, &lite_command);
if let Some(frame) = working_set.delta.scope.last_mut() {
if let Some(alias_id) = alias_id {
frame.aliases.insert(name.clone(), alias_id);
}
}
let (mut result, err) =
parse_builtin_commands(working_set, &lite_command, &expand_aliases_denylist);
let mut result = result.expressions.remove(0);
@ -976,6 +1005,7 @@ pub fn parse_call(
span(&spans[cmd_start..pos]),
&spans[pos..],
decl_id,
expand_aliases_denylist,
);
(
Expression {
@ -992,7 +1022,8 @@ pub fn parse_call(
trace!("parsing: range {:?} ", bytes);
if let (Some(b'.'), Some(b'.')) = (bytes.get(0), bytes.get(1)) {
trace!("-- found leading range indicator");
let (range_expr, range_err) = parse_range(working_set, spans[0]);
let (range_expr, range_err) =
parse_range(working_set, spans[0], expand_aliases_denylist);
if range_err.is_none() {
trace!("-- successfully parsed range");
return (range_expr, range_err);
@ -1001,7 +1032,7 @@ pub fn parse_call(
trace!("parsing: external call");
// Otherwise, try external command
parse_external_call(working_set, spans)
parse_external_call(working_set, spans, expand_aliases_denylist)
}
}
@ -1201,6 +1232,7 @@ pub fn parse_number(token: &[u8], span: Span) -> (Expression, Option<ParseError>
pub fn parse_range(
working_set: &mut StateWorkingSet,
span: Span,
expand_aliases_denylist: &[usize],
) -> (Expression, Option<ParseError>) {
trace!("parsing: range");
@ -1279,7 +1311,12 @@ pub fn parse_range(
None
} else {
let from_span = Span::new(span.start, span.start + dotdot_pos[0]);
match parse_value(working_set, from_span, &SyntaxShape::Number) {
match parse_value(
working_set,
from_span,
&SyntaxShape::Number,
expand_aliases_denylist,
) {
(expression, None) => Some(Box::new(expression)),
_ => {
return (
@ -1294,7 +1331,12 @@ pub fn parse_range(
None
} else {
let to_span = Span::new(range_op_span.end, span.end);
match parse_value(working_set, to_span, &SyntaxShape::Number) {
match parse_value(
working_set,
to_span,
&SyntaxShape::Number,
expand_aliases_denylist,
) {
(expression, None) => Some(Box::new(expression)),
_ => {
return (
@ -1321,7 +1363,12 @@ pub fn parse_range(
let next_op_span = Span::new(span.start + pos, span.start + pos + "..".len());
let next_span = Span::new(next_op_span.end, range_op_span.start);
match parse_value(working_set, next_span, &SyntaxShape::Number) {
match parse_value(
working_set,
next_span,
&SyntaxShape::Number,
expand_aliases_denylist,
) {
(expression, None) => (Some(Box::new(expression)), next_op_span),
_ => {
return (
@ -1354,22 +1401,24 @@ pub fn parse_range(
pub(crate) fn parse_dollar_expr(
working_set: &mut StateWorkingSet,
span: Span,
expand_aliases_denylist: &[usize],
) -> (Expression, Option<ParseError>) {
trace!("parsing: dollar expression");
let contents = working_set.get_span_contents(span);
if contents.starts_with(b"$\"") || contents.starts_with(b"$'") {
parse_string_interpolation(working_set, span)
} else if let (expr, None) = parse_range(working_set, span) {
parse_string_interpolation(working_set, span, expand_aliases_denylist)
} else if let (expr, None) = parse_range(working_set, span, expand_aliases_denylist) {
(expr, None)
} else {
parse_full_cell_path(working_set, None, span)
parse_full_cell_path(working_set, None, span, expand_aliases_denylist)
}
}
pub fn parse_string_interpolation(
working_set: &mut StateWorkingSet,
span: Span,
expand_aliases_denylist: &[usize],
) -> (Expression, Option<ParseError>) {
#[derive(PartialEq, Eq, Debug)]
enum InterpolationMode {
@ -1469,7 +1518,8 @@ pub fn parse_string_interpolation(
end: b + 1,
};
let (expr, err) = parse_full_cell_path(working_set, None, span);
let (expr, err) =
parse_full_cell_path(working_set, None, span, expand_aliases_denylist);
error = error.or(err);
output.push(expr);
}
@ -1515,7 +1565,8 @@ pub fn parse_string_interpolation(
end,
};
let (expr, err) = parse_full_cell_path(working_set, None, span);
let (expr, err) =
parse_full_cell_path(working_set, None, span, expand_aliases_denylist);
error = error.or(err);
output.push(expr);
}
@ -1692,6 +1743,7 @@ pub fn parse_full_cell_path(
working_set: &mut StateWorkingSet,
implicit_head: Option<VarId>,
span: Span,
expand_aliases_denylist: &[usize],
) -> (Expression, Option<ParseError>) {
let full_cell_span = span;
let source = working_set.get_span_contents(span);
@ -1730,7 +1782,7 @@ pub fn parse_full_cell_path(
let (output, err) = lite_parse(&output);
error = error.or(err);
let (output, err) = parse_block(working_set, &output, true);
let (output, err) = parse_block(working_set, &output, true, expand_aliases_denylist);
error = error.or(err);
let block_id = working_set.add_block(output);
@ -1748,7 +1800,8 @@ pub fn parse_full_cell_path(
} else if bytes.starts_with(b"[") {
trace!("parsing: table head of full cell path");
let (output, err) = parse_table_expression(working_set, head.span);
let (output, err) =
parse_table_expression(working_set, head.span, expand_aliases_denylist);
error = error.or(err);
tokens.next();
@ -1756,7 +1809,7 @@ pub fn parse_full_cell_path(
(output, true)
} else if bytes.starts_with(b"{") {
trace!("parsing: record head of full cell path");
let (output, err) = parse_record(working_set, head.span);
let (output, err) = parse_record(working_set, head.span, expand_aliases_denylist);
error = error.or(err);
tokens.next();
@ -2519,6 +2572,7 @@ pub fn parse_type(_working_set: &StateWorkingSet, bytes: &[u8]) -> Type {
pub fn parse_import_pattern(
working_set: &mut StateWorkingSet,
spans: &[Span],
expand_aliases_denylist: &[usize],
) -> (Expression, Option<ParseError>) {
let mut error = None;
@ -2553,8 +2607,12 @@ pub fn parse_import_pattern(
None,
)
} else if tail.starts_with(b"[") {
let (result, err) =
parse_list_expression(working_set, *tail_span, &SyntaxShape::String);
let (result, err) = parse_list_expression(
working_set,
*tail_span,
&SyntaxShape::String,
expand_aliases_denylist,
);
error = error.or(err);
let mut output = vec![];
@ -2725,6 +2783,7 @@ pub fn expand_to_cell_path(
working_set: &mut StateWorkingSet,
expression: &mut Expression,
var_id: VarId,
expand_aliases_denylist: &[usize],
) {
if let Expression {
expr: Expr::String(_),
@ -2733,7 +2792,8 @@ pub fn expand_to_cell_path(
} = expression
{
// Re-parse the string as if it were a cell-path
let (new_expression, _err) = parse_full_cell_path(working_set, Some(var_id), *span);
let (new_expression, _err) =
parse_full_cell_path(working_set, Some(var_id), *span, expand_aliases_denylist);
*expression = new_expression;
}
@ -2742,9 +2802,11 @@ pub fn expand_to_cell_path(
pub fn parse_row_condition(
working_set: &mut StateWorkingSet,
spans: &[Span],
expand_aliases_denylist: &[usize],
) -> (Expression, Option<ParseError>) {
let var_id = working_set.add_variable(b"$it".to_vec(), span(spans), Type::Unknown);
let (expression, err) = parse_math_expression(working_set, spans, Some(var_id));
let (expression, err) =
parse_math_expression(working_set, spans, Some(var_id), expand_aliases_denylist);
let span = span(spans);
let block_id = match expression.expr {
@ -2783,6 +2845,7 @@ pub fn parse_row_condition(
pub fn parse_signature(
working_set: &mut StateWorkingSet,
span: Span,
expand_aliases_denylist: &[usize],
) -> (Expression, Option<ParseError>) {
let bytes = working_set.get_span_contents(span);
@ -2810,7 +2873,8 @@ pub fn parse_signature(
error = error.or_else(|| Some(ParseError::Unclosed("]".into(), Span { start: end, end })));
}
let (sig, err) = parse_signature_helper(working_set, Span { start, end });
let (sig, err) =
parse_signature_helper(working_set, Span { start, end }, expand_aliases_denylist);
error = error.or(err);
(
@ -2827,6 +2891,7 @@ pub fn parse_signature(
pub fn parse_signature_helper(
working_set: &mut StateWorkingSet,
span: Span,
expand_aliases_denylist: &[usize],
) -> (Box<Signature>, Option<ParseError>) {
#[allow(clippy::enum_variant_names)]
enum ParseMode {
@ -3105,8 +3170,12 @@ pub fn parse_signature_helper(
}
ParseMode::DefaultValueMode => {
if let Some(last) = args.last_mut() {
let (expression, err) =
parse_value(working_set, span, &SyntaxShape::Any);
let (expression, err) = parse_value(
working_set,
span,
&SyntaxShape::Any,
expand_aliases_denylist,
);
error = error.or(err);
//TODO check if we're replacing a custom parameter already
@ -3279,6 +3348,7 @@ pub fn parse_list_expression(
working_set: &mut StateWorkingSet,
span: Span,
element_shape: &SyntaxShape,
expand_aliases_denylist: &[usize],
) -> (Expression, Option<ParseError>) {
let bytes = working_set.get_span_contents(span);
@ -3314,8 +3384,13 @@ pub fn parse_list_expression(
let mut spans_idx = 0;
while spans_idx < arg.parts.len() {
let (arg, err) =
parse_multispan_value(working_set, &arg.parts, &mut spans_idx, element_shape);
let (arg, err) = parse_multispan_value(
working_set,
&arg.parts,
&mut spans_idx,
element_shape,
expand_aliases_denylist,
);
error = error.or(err);
if let Some(ref ctype) = contained_type {
@ -3351,6 +3426,7 @@ pub fn parse_list_expression(
pub fn parse_table_expression(
working_set: &mut StateWorkingSet,
original_span: Span,
expand_aliases_denylist: &[usize],
) -> (Expression, Option<ParseError>) {
let bytes = working_set.get_span_contents(original_span);
let mut error = None;
@ -3389,7 +3465,12 @@ pub fn parse_table_expression(
),
1 => {
// List
parse_list_expression(working_set, original_span, &SyntaxShape::Any)
parse_list_expression(
working_set,
original_span,
&SyntaxShape::Any,
expand_aliases_denylist,
)
}
_ => {
let mut table_headers = vec![];
@ -3398,6 +3479,7 @@ pub fn parse_table_expression(
working_set,
output.block[0].commands[0].parts[0],
&SyntaxShape::List(Box::new(SyntaxShape::Any)),
expand_aliases_denylist,
);
error = error.or(err);
@ -3415,6 +3497,7 @@ pub fn parse_table_expression(
working_set,
*part,
&SyntaxShape::List(Box::new(SyntaxShape::Any)),
expand_aliases_denylist,
);
error = error.or(err);
if let Expression {
@ -3460,6 +3543,7 @@ pub fn parse_block_expression(
working_set: &mut StateWorkingSet,
shape: &SyntaxShape,
span: Span,
expand_aliases_denylist: &[usize],
) -> (Expression, Option<ParseError>) {
trace!("parsing: block expression");
@ -3526,7 +3610,8 @@ pub fn parse_block_expression(
start: start_point,
end: end_point,
};
let (signature, err) = parse_signature_helper(working_set, signature_span);
let (signature, err) =
parse_signature_helper(working_set, signature_span, expand_aliases_denylist);
error = error.or(err);
(Some((signature, signature_span)), amt_to_skip)
@ -3584,7 +3669,7 @@ pub fn parse_block_expression(
}
}
let (mut output, err) = parse_block(working_set, &output, false);
let (mut output, err) = parse_block(working_set, &output, false, expand_aliases_denylist);
error = error.or(err);
if let Some(signature) = signature {
@ -3626,6 +3711,7 @@ pub fn parse_value(
working_set: &mut StateWorkingSet,
span: Span,
shape: &SyntaxShape,
expand_aliases_denylist: &[usize],
) -> (Expression, Option<ParseError>) {
let bytes = working_set.get_span_contents(span);
@ -3699,24 +3785,26 @@ pub fn parse_value(
}
match bytes[0] {
b'$' => return parse_dollar_expr(working_set, span),
b'$' => return parse_dollar_expr(working_set, span, expand_aliases_denylist),
b'(' => {
if let (expr, None) = parse_range(working_set, span) {
if let (expr, None) = parse_range(working_set, span, expand_aliases_denylist) {
return (expr, None);
} else {
return parse_full_cell_path(working_set, None, span);
return parse_full_cell_path(working_set, None, span, expand_aliases_denylist);
}
}
b'{' => {
if !matches!(shape, SyntaxShape::Block(..)) {
if let (expr, None) = parse_full_cell_path(working_set, None, span) {
if let (expr, None) =
parse_full_cell_path(working_set, None, span, expand_aliases_denylist)
{
return (expr, None);
}
}
if matches!(shape, SyntaxShape::Block(_)) || matches!(shape, SyntaxShape::Any) {
return parse_block_expression(working_set, shape, span);
return parse_block_expression(working_set, shape, span, expand_aliases_denylist);
} else if matches!(shape, SyntaxShape::Record) {
return parse_record(working_set, span);
return parse_record(working_set, span, expand_aliases_denylist);
} else {
return (
Expression::garbage(span),
@ -3741,7 +3829,8 @@ pub fn parse_value(
match shape {
SyntaxShape::Custom(shape, custom_completion) => {
let (mut expression, err) = parse_value(working_set, span, shape);
let (mut expression, err) =
parse_value(working_set, span, shape, expand_aliases_denylist);
expression.custom_completion = Some(*custom_completion);
(expression, err)
}
@ -3750,14 +3839,14 @@ pub fn parse_value(
SyntaxShape::Duration => parse_duration(working_set, span),
SyntaxShape::DateTime => parse_datetime(working_set, span),
SyntaxShape::Filesize => parse_filesize(working_set, span),
SyntaxShape::Range => parse_range(working_set, span),
SyntaxShape::Range => parse_range(working_set, span, expand_aliases_denylist),
SyntaxShape::Filepath => parse_filepath(working_set, span),
SyntaxShape::GlobPattern => parse_glob_pattern(working_set, span),
SyntaxShape::String => parse_string(working_set, span),
SyntaxShape::Binary => parse_binary(working_set, span),
SyntaxShape::Signature => {
if bytes.starts_with(b"[") {
parse_signature(working_set, span)
parse_signature(working_set, span, expand_aliases_denylist)
} else {
(
Expression::garbage(span),
@ -3767,7 +3856,7 @@ pub fn parse_value(
}
SyntaxShape::List(elem) => {
if bytes.starts_with(b"[") {
parse_list_expression(working_set, span, elem)
parse_list_expression(working_set, span, elem, expand_aliases_denylist)
} else {
(
Expression::garbage(span),
@ -3777,7 +3866,7 @@ pub fn parse_value(
}
SyntaxShape::Table => {
if bytes.starts_with(b"[") {
parse_table_expression(working_set, span)
parse_table_expression(working_set, span, expand_aliases_denylist)
} else {
(
Expression::garbage(span),
@ -3829,7 +3918,7 @@ pub fn parse_value(
SyntaxShape::Any => {
if bytes.starts_with(b"[") {
//parse_value(working_set, span, &SyntaxShape::Table)
parse_full_cell_path(working_set, None, span)
parse_full_cell_path(working_set, None, span, expand_aliases_denylist)
} else {
let shapes = [
SyntaxShape::Binary,
@ -3844,7 +3933,9 @@ pub fn parse_value(
SyntaxShape::String,
];
for shape in shapes.iter() {
if let (s, None) = parse_value(working_set, span, shape) {
if let (s, None) =
parse_value(working_set, span, shape, expand_aliases_denylist)
{
return (s, None);
}
}
@ -3906,6 +3997,7 @@ pub fn parse_math_expression(
working_set: &mut StateWorkingSet,
spans: &[Span],
lhs_row_var_id: Option<VarId>,
expand_aliases_denylist: &[usize],
) -> (Expression, Option<ParseError>) {
// As the expr_stack grows, we increase the required precedence to grow larger
// If, at any time, the operator we're looking at is the same or lower precedence
@ -3923,7 +4015,12 @@ pub fn parse_math_expression(
let mut last_prec = 1000000;
let mut error = None;
let (lhs, err) = parse_value(working_set, spans[0], &SyntaxShape::Any);
let (lhs, err) = parse_value(
working_set,
spans[0],
&SyntaxShape::Any,
expand_aliases_denylist,
);
error = error.or(err);
idx += 1;
@ -3947,7 +4044,12 @@ pub fn parse_math_expression(
break;
}
let (rhs, err) = parse_value(working_set, spans[idx], &SyntaxShape::Any);
let (rhs, err) = parse_value(
working_set,
spans[idx],
&SyntaxShape::Any,
expand_aliases_denylist,
);
error = error.or(err);
if op_prec <= last_prec && expr_stack.len() > 1 {
@ -3965,7 +4067,7 @@ pub fn parse_math_expression(
.expect("internal error: expression stack empty");
if let Some(row_var_id) = lhs_row_var_id {
expand_to_cell_path(working_set, &mut lhs, row_var_id);
expand_to_cell_path(working_set, &mut lhs, row_var_id, expand_aliases_denylist);
}
let (result_ty, err) = math_result_type(working_set, &mut lhs, &mut op, &mut rhs);
@ -3999,7 +4101,7 @@ pub fn parse_math_expression(
.expect("internal error: expression stack empty");
if let Some(row_var_id) = lhs_row_var_id {
expand_to_cell_path(working_set, &mut lhs, row_var_id);
expand_to_cell_path(working_set, &mut lhs, row_var_id, expand_aliases_denylist);
}
let (result_ty, err) = math_result_type(working_set, &mut lhs, &mut op, &mut rhs);
@ -4024,7 +4126,7 @@ pub fn parse_math_expression(
pub fn parse_expression(
working_set: &mut StateWorkingSet,
spans: &[Span],
expand_aliases: bool,
expand_aliases_denylist: &[usize],
) -> (Expression, Option<ParseError>) {
let mut pos = 0;
let mut shorthand = vec![];
@ -4092,56 +4194,110 @@ pub fn parse_expression(
.iter()
.any(|x| x == bytes)
{
parse_math_expression(working_set, &spans[pos..], None)
parse_math_expression(working_set, &spans[pos..], None, expand_aliases_denylist)
} else {
// For now, check for special parses of certain keywords
match bytes {
b"def" => (
parse_call(working_set, &spans[pos..], expand_aliases, spans[0]).0,
parse_call(
working_set,
&spans[pos..],
spans[0],
expand_aliases_denylist,
)
.0,
Some(ParseError::BuiltinCommandInPipeline("def".into(), spans[0])),
),
b"extern" => (
parse_call(working_set, &spans[pos..], expand_aliases, spans[0]).0,
parse_call(
working_set,
&spans[pos..],
spans[0],
expand_aliases_denylist,
)
.0,
Some(ParseError::BuiltinCommandInPipeline(
"extern".into(),
spans[0],
)),
),
b"let" => (
parse_call(working_set, &spans[pos..], expand_aliases, spans[0]).0,
parse_call(
working_set,
&spans[pos..],
spans[0],
expand_aliases_denylist,
)
.0,
Some(ParseError::BuiltinCommandInPipeline("let".into(), spans[0])),
),
b"alias" => (
parse_call(working_set, &spans[pos..], expand_aliases, spans[0]).0,
parse_call(
working_set,
&spans[pos..],
spans[0],
expand_aliases_denylist,
)
.0,
Some(ParseError::BuiltinCommandInPipeline(
"alias".into(),
spans[0],
)),
),
b"module" => (
parse_call(working_set, &spans[pos..], expand_aliases, spans[0]).0,
parse_call(
working_set,
&spans[pos..],
spans[0],
expand_aliases_denylist,
)
.0,
Some(ParseError::BuiltinCommandInPipeline(
"module".into(),
spans[0],
)),
),
b"use" => (
parse_call(working_set, &spans[pos..], expand_aliases, spans[0]).0,
parse_call(
working_set,
&spans[pos..],
spans[0],
expand_aliases_denylist,
)
.0,
Some(ParseError::BuiltinCommandInPipeline("use".into(), spans[0])),
),
b"source" => (
parse_call(working_set, &spans[pos..], expand_aliases, spans[0]).0,
parse_call(
working_set,
&spans[pos..],
spans[0],
expand_aliases_denylist,
)
.0,
Some(ParseError::BuiltinCommandInPipeline(
"source".into(),
spans[0],
)),
),
b"export" => (
parse_call(working_set, &spans[pos..], expand_aliases, spans[0]).0,
parse_call(
working_set,
&spans[pos..],
spans[0],
expand_aliases_denylist,
)
.0,
Some(ParseError::UnexpectedKeyword("export".into(), spans[0])),
),
b"hide" => (
parse_call(working_set, &spans[pos..], expand_aliases, spans[0]).0,
parse_call(
working_set,
&spans[pos..],
spans[0],
expand_aliases_denylist,
)
.0,
Some(ParseError::BuiltinCommandInPipeline(
"hide".into(),
spans[0],
@ -4149,15 +4305,26 @@ pub fn parse_expression(
),
#[cfg(feature = "plugin")]
b"register" => (
parse_call(working_set, &spans[pos..], expand_aliases, spans[0]).0,
parse_call(
working_set,
&spans[pos..],
spans[0],
expand_aliases_denylist,
)
.0,
Some(ParseError::BuiltinCommandInPipeline(
"plugin".into(),
spans[0],
)),
),
b"for" => parse_for(working_set, spans),
_ => parse_call(working_set, &spans[pos..], expand_aliases, spans[0]),
b"for" => parse_for(working_set, spans, expand_aliases_denylist),
_ => parse_call(
working_set,
&spans[pos..],
spans[0],
expand_aliases_denylist,
),
}
};
@ -4240,21 +4407,22 @@ pub fn parse_variable(
pub fn parse_builtin_commands(
working_set: &mut StateWorkingSet,
lite_command: &LiteCommand,
expand_aliases_denylist: &[usize],
) -> (Pipeline, Option<ParseError>) {
let name = working_set.get_span_contents(lite_command.parts[0]);
match name {
b"def" | b"def-env" => parse_def(working_set, lite_command),
b"extern" => parse_extern(working_set, lite_command),
b"let" => parse_let(working_set, &lite_command.parts),
b"def" | b"def-env" => parse_def(working_set, lite_command, expand_aliases_denylist),
b"extern" => parse_extern(working_set, lite_command, expand_aliases_denylist),
b"let" => parse_let(working_set, &lite_command.parts, expand_aliases_denylist),
b"for" => {
let (expr, err) = parse_for(working_set, &lite_command.parts);
let (expr, err) = parse_for(working_set, &lite_command.parts, expand_aliases_denylist);
(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"alias" => parse_alias(working_set, &lite_command.parts, expand_aliases_denylist),
b"module" => parse_module(working_set, &lite_command.parts, expand_aliases_denylist),
b"use" => parse_use(working_set, &lite_command.parts, expand_aliases_denylist),
b"source" => parse_source(working_set, &lite_command.parts, expand_aliases_denylist),
b"export" => (
garbage_pipeline(&lite_command.parts),
Some(ParseError::UnexpectedKeyword(
@ -4262,11 +4430,12 @@ pub fn parse_builtin_commands(
lite_command.parts[0],
)),
),
b"hide" => parse_hide(working_set, &lite_command.parts),
b"hide" => parse_hide(working_set, &lite_command.parts, expand_aliases_denylist),
#[cfg(feature = "plugin")]
b"register" => parse_register(working_set, &lite_command.parts),
b"register" => parse_register(working_set, &lite_command.parts, expand_aliases_denylist),
_ => {
let (expr, err) = parse_expression(working_set, &lite_command.parts, true);
let (expr, err) =
parse_expression(working_set, &lite_command.parts, expand_aliases_denylist);
(Pipeline::from_vec(vec![expr]), err)
}
}
@ -4275,6 +4444,7 @@ pub fn parse_builtin_commands(
pub fn parse_record(
working_set: &mut StateWorkingSet,
span: Span,
expand_aliases_denylist: &[usize],
) -> (Expression, Option<ParseError>) {
let bytes = working_set.get_span_contents(span);
@ -4312,7 +4482,12 @@ pub fn parse_record(
let mut idx = 0;
while idx < tokens.len() {
let (field, err) = parse_value(working_set, tokens[idx].span, &SyntaxShape::Any);
let (field, err) = parse_value(
working_set,
tokens[idx].span,
&SyntaxShape::Any,
expand_aliases_denylist,
);
error = error.or(err);
idx += 1;
@ -4331,7 +4506,12 @@ pub fn parse_record(
Some(ParseError::Expected("record".into(), span)),
);
}
let (value, err) = parse_value(working_set, tokens[idx].span, &SyntaxShape::Any);
let (value, err) = parse_value(
working_set,
tokens[idx].span,
&SyntaxShape::Any,
expand_aliases_denylist,
);
error = error.or(err);
idx += 1;
@ -4353,6 +4533,7 @@ pub fn parse_block(
working_set: &mut StateWorkingSet,
lite_block: &LiteBlock,
scoped: bool,
expand_aliases_denylist: &[usize],
) -> (Block, Option<ParseError>) {
trace!("parsing block: {:?}", lite_block);
@ -4366,7 +4547,11 @@ pub fn parse_block(
// that share the same block can see each other
for pipeline in &lite_block.block {
if pipeline.commands.len() == 1 {
if let Some(err) = parse_def_predecl(working_set, &pipeline.commands[0].parts) {
if let Some(err) = parse_def_predecl(
working_set,
&pipeline.commands[0].parts,
expand_aliases_denylist,
) {
error = error.or(Some(err));
}
}
@ -4382,7 +4567,8 @@ pub fn parse_block(
.commands
.iter()
.map(|command| {
let (expr, err) = parse_expression(working_set, &command.parts, true);
let (expr, err) =
parse_expression(working_set, &command.parts, expand_aliases_denylist);
if error.is_none() {
error = err;
@ -4402,8 +4588,11 @@ pub fn parse_block(
expressions: output,
}
} else {
let (mut pipeline, err) =
parse_builtin_commands(working_set, &pipeline.commands[0]);
let (mut pipeline, err) = parse_builtin_commands(
working_set,
&pipeline.commands[0],
expand_aliases_denylist,
);
if idx == 0 {
if let Some(let_decl_id) = working_set.find_decl(b"let") {
@ -4776,6 +4965,7 @@ pub fn parse(
fname: Option<&str>,
contents: &[u8],
scoped: bool,
expand_aliases_denylist: &[usize],
) -> (Block, Option<ParseError>) {
trace!("starting top-level parse");
@ -4796,7 +4986,7 @@ pub fn parse(
let (output, err) = lite_parse(&output);
error = error.or(err);
let (mut output, err) = parse_block(working_set, &output, scoped);
let (mut output, err) = parse_block(working_set, &output, scoped, expand_aliases_denylist);
error = error.or(err);
let mut seen = vec![];

View File

@ -46,7 +46,7 @@ pub fn parse_int() {
let engine_state = EngineState::new();
let mut working_set = StateWorkingSet::new(&engine_state);
let (block, err) = parse(&mut working_set, None, b"3", true);
let (block, err) = parse(&mut working_set, None, b"3", true, &[]);
assert!(err.is_none());
assert!(block.len() == 1);
@ -69,7 +69,7 @@ pub fn parse_call() {
let sig = Signature::build("foo").named("--jazz", SyntaxShape::Int, "jazz!!", Some('j'));
working_set.add_decl(sig.predeclare());
let (block, err) = parse(&mut working_set, None, b"foo", true);
let (block, err) = parse(&mut working_set, None, b"foo", true, &[]);
assert!(err.is_none());
assert!(block.len() == 1);
@ -94,7 +94,7 @@ pub fn parse_call_missing_flag_arg() {
let sig = Signature::build("foo").named("jazz", SyntaxShape::Int, "jazz!!", Some('j'));
working_set.add_decl(sig.predeclare());
let (_, err) = parse(&mut working_set, None, b"foo --jazz", true);
let (_, err) = parse(&mut working_set, None, b"foo --jazz", true, &[]);
assert!(matches!(err, Some(ParseError::MissingFlagParam(..))));
}
@ -106,7 +106,7 @@ pub fn parse_call_missing_short_flag_arg() {
let sig = Signature::build("foo").named("--jazz", SyntaxShape::Int, "jazz!!", Some('j'));
working_set.add_decl(sig.predeclare());
let (_, err) = parse(&mut working_set, None, b"foo -j", true);
let (_, err) = parse(&mut working_set, None, b"foo -j", true, &[]);
assert!(matches!(err, Some(ParseError::MissingFlagParam(..))));
}
@ -119,7 +119,7 @@ pub fn parse_call_too_many_shortflag_args() {
.named("--jazz", SyntaxShape::Int, "jazz!!", Some('j'))
.named("--math", SyntaxShape::Int, "math!!", Some('m'));
working_set.add_decl(sig.predeclare());
let (_, err) = parse(&mut working_set, None, b"foo -mj", true);
let (_, err) = parse(&mut working_set, None, b"foo -mj", true, &[]);
assert!(matches!(
err,
Some(ParseError::ShortFlagBatchCantTakeArg(..))
@ -133,7 +133,7 @@ pub fn parse_call_unknown_shorthand() {
let sig = Signature::build("foo").switch("--jazz", "jazz!!", Some('j'));
working_set.add_decl(sig.predeclare());
let (_, err) = parse(&mut working_set, None, b"foo -mj", true);
let (_, err) = parse(&mut working_set, None, b"foo -mj", true, &[]);
assert!(matches!(err, Some(ParseError::UnknownFlag(..))));
}
@ -144,7 +144,7 @@ pub fn parse_call_extra_positional() {
let sig = Signature::build("foo").switch("--jazz", "jazz!!", Some('j'));
working_set.add_decl(sig.predeclare());
let (_, err) = parse(&mut working_set, None, b"foo -j 100", true);
let (_, err) = parse(&mut working_set, None, b"foo -j 100", true, &[]);
assert!(matches!(err, Some(ParseError::ExtraPositional(..))));
}
@ -155,7 +155,7 @@ pub fn parse_call_missing_req_positional() {
let sig = Signature::build("foo").required("jazz", SyntaxShape::Int, "jazz!!");
working_set.add_decl(sig.predeclare());
let (_, err) = parse(&mut working_set, None, b"foo", true);
let (_, err) = parse(&mut working_set, None, b"foo", true, &[]);
assert!(matches!(err, Some(ParseError::MissingPositional(..))));
}
@ -166,7 +166,7 @@ pub fn parse_call_missing_req_flag() {
let sig = Signature::build("foo").required_named("--jazz", SyntaxShape::Int, "jazz!!", None);
working_set.add_decl(sig.predeclare());
let (_, err) = parse(&mut working_set, None, b"foo", true);
let (_, err) = parse(&mut working_set, None, b"foo", true, &[]);
assert!(matches!(err, Some(ParseError::MissingRequiredFlag(..))));
}
@ -174,7 +174,7 @@ pub fn parse_call_missing_req_flag() {
fn test_nothing_comparisson_eq() {
let engine_state = EngineState::new();
let mut working_set = StateWorkingSet::new(&engine_state);
let (block, err) = parse(&mut working_set, None, b"2 == $nothing", true);
let (block, err) = parse(&mut working_set, None, b"2 == $nothing", true, &[]);
assert!(err.is_none());
assert!(block.len() == 1);
@ -194,7 +194,7 @@ fn test_nothing_comparisson_eq() {
fn test_nothing_comparisson_neq() {
let engine_state = EngineState::new();
let mut working_set = StateWorkingSet::new(&engine_state);
let (block, err) = parse(&mut working_set, None, b"2 != $nothing", true);
let (block, err) = parse(&mut working_set, None, b"2 != $nothing", true, &[]);
assert!(err.is_none());
assert!(block.len() == 1);
@ -219,7 +219,7 @@ mod range {
let engine_state = EngineState::new();
let mut working_set = StateWorkingSet::new(&engine_state);
let (block, err) = parse(&mut working_set, None, b"0..10", true);
let (block, err) = parse(&mut working_set, None, b"0..10", true, &[]);
assert!(err.is_none());
assert!(block.len() == 1);
@ -248,7 +248,7 @@ mod range {
let engine_state = EngineState::new();
let mut working_set = StateWorkingSet::new(&engine_state);
let (block, err) = parse(&mut working_set, None, b"0..<10", true);
let (block, err) = parse(&mut working_set, None, b"0..<10", true, &[]);
assert!(err.is_none());
assert!(block.len() == 1);
@ -277,7 +277,7 @@ mod range {
let engine_state = EngineState::new();
let mut working_set = StateWorkingSet::new(&engine_state);
let (block, err) = parse(&mut working_set, None, b"10..0", true);
let (block, err) = parse(&mut working_set, None, b"10..0", true, &[]);
assert!(err.is_none());
assert!(block.len() == 1);
@ -306,7 +306,7 @@ mod range {
let engine_state = EngineState::new();
let mut working_set = StateWorkingSet::new(&engine_state);
let (block, err) = parse(&mut working_set, None, b"(3 - 3)..<(8 + 2)", true);
let (block, err) = parse(&mut working_set, None, b"(3 - 3)..<(8 + 2)", true, &[]);
assert!(err.is_none());
assert!(block.len() == 1);
@ -337,7 +337,7 @@ mod range {
working_set.add_decl(Box::new(Let));
let (block, err) = parse(&mut working_set, None, b"let a = 2; $a..10", true);
let (block, err) = parse(&mut working_set, None, b"let a = 2; $a..10", true, &[]);
assert!(err.is_none());
assert!(block.len() == 2);
@ -368,7 +368,13 @@ mod range {
working_set.add_decl(Box::new(Let));
let (block, err) = parse(&mut working_set, None, b"let a = 2; $a..<($a + 10)", true);
let (block, err) = parse(
&mut working_set,
None,
b"let a = 2; $a..<($a + 10)",
true,
&[],
);
assert!(err.is_none());
assert!(block.len() == 2);
@ -397,7 +403,7 @@ mod range {
let engine_state = EngineState::new();
let mut working_set = StateWorkingSet::new(&engine_state);
let (block, err) = parse(&mut working_set, None, b"0..", true);
let (block, err) = parse(&mut working_set, None, b"0..", true, &[]);
assert!(err.is_none());
assert!(block.len() == 1);
@ -426,7 +432,7 @@ mod range {
let engine_state = EngineState::new();
let mut working_set = StateWorkingSet::new(&engine_state);
let (block, err) = parse(&mut working_set, None, b"..10", true);
let (block, err) = parse(&mut working_set, None, b"..10", true, &[]);
assert!(err.is_none());
assert!(block.len() == 1);
@ -455,7 +461,7 @@ mod range {
let engine_state = EngineState::new();
let mut working_set = StateWorkingSet::new(&engine_state);
let (block, err) = parse(&mut working_set, None, b"-10..-3", true);
let (block, err) = parse(&mut working_set, None, b"-10..-3", true, &[]);
assert!(err.is_none());
assert!(block.len() == 1);
@ -484,7 +490,7 @@ mod range {
let engine_state = EngineState::new();
let mut working_set = StateWorkingSet::new(&engine_state);
let (block, err) = parse(&mut working_set, None, b"2.0..4.0..10.0", true);
let (block, err) = parse(&mut working_set, None, b"2.0..4.0..10.0", true, &[]);
assert!(err.is_none());
assert!(block.len() == 1);
@ -513,7 +519,7 @@ mod range {
let engine_state = EngineState::new();
let mut working_set = StateWorkingSet::new(&engine_state);
let (_, err) = parse(&mut working_set, None, b"(0)..\"a\"", true);
let (_, err) = parse(&mut working_set, None, b"(0)..\"a\"", true, &[]);
assert!(err.is_some());
}

View File

@ -844,10 +844,44 @@ impl<'a> StateWorkingSet<'a> {
None
}
pub fn use_alias(&mut self, alias_id: &AliasId) {
let mut visibility: Visibility = Visibility::new();
// Since we can mutate scope frames in delta, remove the id directly
for scope in self.delta.scope.iter_mut().rev() {
visibility.append(&scope.visibility);
if !visibility.is_alias_id_visible(alias_id) {
// Hide alias only if it's not already hidden
scope.visibility.use_alias_id(alias_id);
return;
}
}
// We cannot mutate the permanent state => store the information in the current scope frame
let last_scope_frame = self
.delta
.scope
.last_mut()
.expect("internal error: missing required scope frame");
for scope in self.permanent_state.scope.iter().rev() {
visibility.append(&scope.visibility);
if !visibility.is_alias_id_visible(alias_id) {
// Hide alias only if it's not already hidden
last_scope_frame.visibility.use_alias_id(alias_id);
return;
}
}
}
pub fn hide_alias(&mut self, name: &[u8]) -> Option<AliasId> {
let mut visibility: Visibility = Visibility::new();
// // Since we can mutate scope frames in delta, remove the id directly
// Since we can mutate scope frames in delta, remove the id directly
for scope in self.delta.scope.iter_mut().rev() {
visibility.append(&scope.visibility);

View File

@ -279,7 +279,13 @@ fn parse_commandline_args(
let mut working_set = StateWorkingSet::new(engine_state);
working_set.add_decl(Box::new(Nu));
let (output, err) = parse(&mut working_set, None, commandline_args.as_bytes(), false);
let (output, err) = parse(
&mut working_set,
None,
commandline_args.as_bytes(),
false,
&[],
);
if let Some(err) = err {
report_error(&working_set, &err);

View File

@ -581,6 +581,17 @@ fn block_params_override() {
assert!(actual.err.contains("variable not found"));
}
#[test]
fn alias_reuse() {
let actual = nu!(
cwd: ".",
r#"alias foo = echo bob; foo; foo"#
);
assert!(actual.out.contains("bob"));
assert!(actual.err.is_empty());
}
#[test]
fn block_params_override_correct() {
let actual = nu!(