Remove shape-directed import pattern parsing (#7570)

This commit is contained in:
Jakub Žádník 2022-12-22 16:36:13 +02:00 committed by GitHub
parent 74656bf976
commit 23a5c5dc09
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 121 additions and 81 deletions

View File

@ -66,6 +66,7 @@ impl Completer for CustomCompletion {
], ],
redirect_stdout: true, redirect_stdout: true,
redirect_stderr: true, redirect_stderr: true,
parser_info: vec![],
}, },
PipelineData::empty(), PipelineData::empty(),
); );

View File

@ -17,7 +17,12 @@ impl Command for ExportUse {
fn signature(&self) -> nu_protocol::Signature { fn signature(&self) -> nu_protocol::Signature {
Signature::build("export use") Signature::build("export use")
.input_output_types(vec![(Type::Nothing, Type::Nothing)]) .input_output_types(vec![(Type::Nothing, Type::Nothing)])
.required("pattern", SyntaxShape::ImportPattern, "import pattern") .required("module", SyntaxShape::String, "Module or module file")
.optional(
"members",
SyntaxShape::Any,
"Which members of the module to import",
)
.category(Category::Core) .category(Category::Core)
} }

View File

@ -15,7 +15,12 @@ impl Command for Hide {
fn signature(&self) -> nu_protocol::Signature { fn signature(&self) -> nu_protocol::Signature {
Signature::build("hide") Signature::build("hide")
.input_output_types(vec![(Type::Nothing, Type::Nothing)]) .input_output_types(vec![(Type::Nothing, Type::Nothing)])
.required("pattern", SyntaxShape::ImportPattern, "import pattern") .required("module", SyntaxShape::String, "Module or module file")
.optional(
"members",
SyntaxShape::Any,
"Which members of the module to import",
)
.category(Category::Core) .category(Category::Core)
} }
@ -44,7 +49,7 @@ This command is a parser keyword. For details, check:
let env_var_name = if let Some(Expression { let env_var_name = if let Some(Expression {
expr: Expr::ImportPattern(pat), expr: Expr::ImportPattern(pat),
.. ..
}) = call.positional_nth(0) }) = call.parser_info_nth(0)
{ {
Spanned { Spanned {
item: String::from_utf8_lossy(&pat.head.name).to_string(), item: String::from_utf8_lossy(&pat.head.name).to_string(),

View File

@ -66,7 +66,7 @@ impl Command for OverlayUse {
let mut name_arg: Spanned<String> = call.req(engine_state, caller_stack, 0)?; let mut name_arg: Spanned<String> = call.req(engine_state, caller_stack, 0)?;
name_arg.item = trim_quotes_str(&name_arg.item).to_string(); name_arg.item = trim_quotes_str(&name_arg.item).to_string();
let maybe_origin_module_id = if let Some(overlay_expr) = call.positional_nth(0) { let maybe_origin_module_id = if let Some(overlay_expr) = call.parser_info_nth(0) {
if let Expr::Overlay(module_id) = overlay_expr.expr { if let Expr::Overlay(module_id) = overlay_expr.expr {
module_id module_id
} else { } else {

View File

@ -20,7 +20,12 @@ impl Command for Use {
fn signature(&self) -> nu_protocol::Signature { fn signature(&self) -> nu_protocol::Signature {
Signature::build("use") Signature::build("use")
.input_output_types(vec![(Type::Nothing, Type::Nothing)]) .input_output_types(vec![(Type::Nothing, Type::Nothing)])
.required("pattern", SyntaxShape::ImportPattern, "import pattern") .required("module", SyntaxShape::String, "Module or module file")
.optional(
"members",
SyntaxShape::Any,
"Which members of the module to import",
)
.category(Category::Core) .category(Category::Core)
} }
@ -43,7 +48,7 @@ impl Command for Use {
let import_pattern = if let Some(Expression { let import_pattern = if let Some(Expression {
expr: Expr::ImportPattern(pat), expr: Expr::ImportPattern(pat),
.. ..
}) = call.positional_nth(0) }) = call.parser_info_nth(0)
{ {
pat pat
} else { } else {

View File

@ -45,7 +45,7 @@ impl Command for Source {
) -> Result<PipelineData, ShellError> { ) -> Result<PipelineData, ShellError> {
// Note: this hidden positional is the block_id that corresponded to the 0th position // Note: this hidden positional is the block_id that corresponded to the 0th position
// it is put here by the parser // it is put here by the parser
let block_id: i64 = call.req(engine_state, stack, 1)?; let block_id: i64 = call.req_parser_info(engine_state, stack, 0)?;
let block = engine_state.get_block(block_id as usize).clone(); let block = engine_state.get_block(block_id as usize).clone();
eval_block( eval_block(

View File

@ -42,7 +42,7 @@ impl Command for SourceEnv {
// Note: this hidden positional is the block_id that corresponded to the 0th position // Note: this hidden positional is the block_id that corresponded to the 0th position
// it is put here by the parser // it is put here by the parser
let block_id: i64 = call.req(engine_state, caller_stack, 1)?; let block_id: i64 = call.req_parser_info(engine_state, caller_stack, 0)?;
// Set the currently evaluated directory (file-relative PWD) // Set the currently evaluated directory (file-relative PWD)
let mut parent = if let Some(path) = let mut parent = if let Some(path) =

View File

@ -34,6 +34,13 @@ pub trait CallExt {
stack: &mut Stack, stack: &mut Stack,
pos: usize, pos: usize,
) -> Result<T, ShellError>; ) -> Result<T, ShellError>;
fn req_parser_info<T: FromValue>(
&self,
engine_state: &EngineState,
stack: &mut Stack,
pos: usize,
) -> Result<T, ShellError>;
} }
impl CallExt for Call { impl CallExt for Call {
@ -99,4 +106,23 @@ impl CallExt for Call {
)) ))
} }
} }
fn req_parser_info<T: FromValue>(
&self,
engine_state: &EngineState,
stack: &mut Stack,
pos: usize,
) -> Result<T, ShellError> {
if let Some(expr) = self.parser_info_nth(pos) {
let result = eval_expression(engine_state, stack, expr)?;
FromValue::from_value(&result)
} else if self.parser_info.is_empty() {
Err(ShellError::AccessEmptyContent(self.head))
} else {
Err(ShellError::AccessBeyondEnd(
self.parser_info.len() - 1,
self.head,
))
}
}
} }

View File

@ -814,6 +814,7 @@ pub fn eval_element_with_input(
], ],
redirect_stdout: false, redirect_stdout: false,
redirect_stderr: false, redirect_stderr: false,
parser_info: vec![],
}, },
input, input,
) )

View File

@ -1,4 +1,3 @@
use crate::eval::{eval_constant, value_as_string};
use log::trace; use log::trace;
use nu_path::canonicalize_with; use nu_path::canonicalize_with;
use nu_protocol::{ use nu_protocol::{
@ -17,13 +16,14 @@ static LIB_DIRS_ENV: &str = "NU_LIB_DIRS";
static PLUGIN_DIRS_ENV: &str = "NU_PLUGIN_DIRS"; static PLUGIN_DIRS_ENV: &str = "NU_PLUGIN_DIRS";
use crate::{ use crate::{
eval::{eval_constant, value_as_string},
known_external::KnownExternal, known_external::KnownExternal,
lex, lex,
lite_parser::{lite_parse, LiteCommand, LiteElement}, lite_parser::{lite_parse, LiteCommand, LiteElement},
parser::{ parser::{
check_call, check_name, garbage, garbage_pipeline, parse, parse_internal_call, check_call, check_name, garbage, garbage_pipeline, parse, parse_import_pattern,
parse_multispan_value, parse_signature, parse_string, parse_value, parse_var_with_opt_type, parse_internal_call, parse_multispan_value, parse_signature, parse_string, parse_value,
trim_quotes, ParsedInternalCall, parse_var_with_opt_type, trim_quotes, ParsedInternalCall,
}, },
unescape_unquote_string, ParseError, unescape_unquote_string, ParseError,
}; };
@ -578,6 +578,7 @@ pub fn parse_alias(
decl_id, decl_id,
redirect_stdout: true, redirect_stdout: true,
redirect_stderr: false, redirect_stderr: false,
parser_info: vec![],
})); }));
return ( return (
Pipeline::from_vec(vec![Expression { Pipeline::from_vec(vec![Expression {
@ -840,6 +841,7 @@ pub fn parse_export_in_module(
arguments: vec![], arguments: vec![],
redirect_stdout: true, redirect_stdout: true,
redirect_stderr: false, redirect_stderr: false,
parser_info: vec![],
}); });
let exportables = if let Some(kw_span) = spans.get(1) { let exportables = if let Some(kw_span) = spans.get(1) {
@ -1505,6 +1507,7 @@ pub fn parse_module(
], ],
redirect_stdout: true, redirect_stdout: true,
redirect_stderr: false, redirect_stderr: false,
parser_info: vec![],
}); });
( (
@ -1562,7 +1565,7 @@ pub fn parse_use(
); );
} }
let (call, call_span, use_decl_id) = match working_set.find_decl(b"use", &Type::Any) { let (call, call_span, args_spans) = match working_set.find_decl(b"use", &Type::Any) {
Some(decl_id) => { Some(decl_id) => {
let (command_spans, rest_spans) = spans.split_at(split_id); let (command_spans, rest_spans) = spans.split_at(split_id);
@ -1595,7 +1598,7 @@ pub fn parse_use(
); );
} }
(call, call_span, decl_id) (call, call_span, rest_spans)
} }
None => { None => {
return ( return (
@ -1609,34 +1612,31 @@ pub fn parse_use(
} }
}; };
let import_pattern = if let Some(expr) = call.positional_nth(0) { let mut error = None;
if let Some(pattern) = expr.as_import_pattern() {
pattern let (import_pattern_expr, err) =
parse_import_pattern(working_set, args_spans, expand_aliases_denylist);
error = error.or(err);
let import_pattern = if let Expression {
expr: Expr::ImportPattern(import_pattern),
..
} = &import_pattern_expr
{
import_pattern.clone()
} else { } else {
return ( return (
garbage_pipeline(spans), garbage_pipeline(spans),
vec![], vec![],
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(),
expr.span, import_pattern_expr.span,
)),
);
}
} else {
return (
garbage_pipeline(spans),
vec![],
Some(ParseError::UnknownState(
"internal error: Missing required positional after call parsing".into(),
call_span,
)), )),
); );
}; };
let cwd = working_set.get_cwd(); let cwd = working_set.get_cwd();
let mut error = None;
// TODO: Add checking for importing too long import patterns, e.g.: // TODO: Add checking for importing too long import patterns, e.g.:
// > use spam foo non existent names here do not throw error // > use spam foo non existent names here do not throw error
let (import_pattern, module) = if let Some(module_id) = import_pattern.head.id { let (import_pattern, module) = if let Some(module_id) = import_pattern.head.id {
@ -1842,18 +1842,13 @@ pub fn parse_use(
// Create a new Use command call to pass the new import pattern // Create a new Use command call to pass the new import pattern
let import_pattern_expr = Expression { let import_pattern_expr = Expression {
expr: Expr::ImportPattern(import_pattern), expr: Expr::ImportPattern(import_pattern),
span: span(&spans[1..]), span: span(args_spans),
ty: Type::List(Box::new(Type::String)), ty: Type::Any,
custom_completion: None, custom_completion: None,
}; };
let call = Box::new(Call { let mut call = call;
head: span(spans.split_at(split_id).0), call.add_parser_info(import_pattern_expr);
decl_id: use_decl_id,
arguments: vec![Argument::Positional(import_pattern_expr)],
redirect_stdout: true,
redirect_stderr: false,
});
( (
Pipeline::from_vec(vec![Expression { Pipeline::from_vec(vec![Expression {
@ -1882,7 +1877,7 @@ pub fn parse_hide(
); );
} }
let (call, call_span, hide_decl_id) = match working_set.find_decl(b"hide", &Type::Any) { let (call, args_spans) = match working_set.find_decl(b"hide", &Type::Any) {
Some(decl_id) => { Some(decl_id) => {
let ParsedInternalCall { let ParsedInternalCall {
call, call,
@ -1912,7 +1907,7 @@ pub fn parse_hide(
); );
} }
(call, call_span, decl_id) (call, &spans[1..])
} }
None => { None => {
return ( return (
@ -1925,29 +1920,28 @@ pub fn parse_hide(
} }
}; };
let import_pattern = if let Some(expr) = call.positional_nth(0) { let mut error = None;
if let Some(pattern) = expr.as_import_pattern() {
pattern let (import_pattern_expr, err) =
parse_import_pattern(working_set, args_spans, expand_aliases_denylist);
error = error.or(err);
let import_pattern = if let Expression {
expr: Expr::ImportPattern(import_pattern),
..
} = &import_pattern_expr
{
import_pattern.clone()
} else { } else {
return ( return (
garbage_pipeline(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, import_pattern_expr.span,
)),
);
}
} else {
return (
garbage_pipeline(spans),
Some(ParseError::UnknownState(
"internal error: Missing required positional after call parsing".into(),
call_span,
)), )),
); );
}; };
let mut error = None;
let bytes = working_set.get_span_contents(spans[0]); let bytes = working_set.get_span_contents(spans[0]);
if bytes == b"hide" && spans.len() >= 2 { if bytes == b"hide" && spans.len() >= 2 {
@ -2054,18 +2048,13 @@ pub fn parse_hide(
// Create a new Use command call to pass the new import pattern // Create a new Use command call to pass the new import pattern
let import_pattern_expr = Expression { let import_pattern_expr = Expression {
expr: Expr::ImportPattern(import_pattern), expr: Expr::ImportPattern(import_pattern),
span: span(&spans[1..]), span: span(args_spans),
ty: Type::List(Box::new(Type::String)), ty: Type::Any,
custom_completion: None, custom_completion: None,
}; };
let call = Box::new(Call { let mut call = call;
head: spans[0], call.add_parser_info(import_pattern_expr);
decl_id: hide_decl_id,
arguments: vec![Argument::Positional(import_pattern_expr)],
redirect_stdout: true,
redirect_stderr: false,
});
( (
Pipeline::from_vec(vec![Expression { Pipeline::from_vec(vec![Expression {
@ -2612,13 +2601,16 @@ pub fn parse_overlay_use(
// Change the call argument to include the Overlay expression with the module ID // Change the call argument to include the Overlay expression with the module ID
let mut call = call; let mut call = call;
if let Some(overlay_expr) = call.positional_nth_mut(0) { call.add_parser_info(Expression {
overlay_expr.expr = Expr::Overlay(if is_module_updated { expr: Expr::Overlay(if is_module_updated {
Some(origin_module_id) Some(origin_module_id)
} else { } else {
None None
}),
span: overlay_name_span,
ty: Type::Any,
custom_completion: None,
}); });
} // no need to check for else since it was already checked
let pipeline = Pipeline::from_vec(vec![Expression { let pipeline = Pipeline::from_vec(vec![Expression {
expr: Expr::Call(call), expr: Expr::Call(call),
@ -2836,6 +2828,7 @@ pub fn parse_let_or_const(
], ],
redirect_stdout: true, redirect_stdout: true,
redirect_stderr: false, redirect_stderr: false,
parser_info: vec![],
}); });
return ( return (
@ -2957,6 +2950,7 @@ pub fn parse_mut(
], ],
redirect_stdout: true, redirect_stdout: true,
redirect_stderr: false, redirect_stderr: false,
parser_info: vec![],
}); });
return ( return (
@ -3131,7 +3125,7 @@ pub fn parse_source(
// FIXME: Adding this expression to the positional creates a syntax highlighting error // FIXME: Adding this expression to the positional creates a syntax highlighting error
// after writing `source example.nu` // after writing `source example.nu`
call_with_block.add_positional(Expression { call_with_block.add_parser_info(Expression {
expr: Expr::Int(block_id as i64), expr: Expr::Int(block_id as i64),
span: spans[1], span: spans[1],
ty: Type::Any, ty: Type::Any,

View File

@ -695,16 +695,6 @@ pub fn parse_multispan_value(
(arg, error) (arg, error)
} }
SyntaxShape::ImportPattern => {
trace!("parsing: import pattern");
let (arg, err) =
parse_import_pattern(working_set, &spans[*spans_idx..], expand_aliases_denylist);
error = error.or(err);
*spans_idx = spans.len() - 1;
(arg, error)
}
SyntaxShape::Keyword(keyword, arg) => { SyntaxShape::Keyword(keyword, arg) => {
trace!( trace!(
"parsing: keyword({}) {:?}", "parsing: keyword({}) {:?}",
@ -5171,6 +5161,7 @@ pub fn parse_expression(
arguments, arguments,
redirect_stdout: true, redirect_stdout: true,
redirect_stderr: false, redirect_stderr: false,
parser_info: vec![],
})); }));
( (
@ -5904,6 +5895,7 @@ fn wrap_expr_with_collect(working_set: &mut StateWorkingSet, expr: &Expression)
decl_id, decl_id,
redirect_stdout: true, redirect_stdout: true,
redirect_stderr: false, redirect_stderr: false,
parser_info: vec![],
})), })),
span, span,
ty: Type::String, ty: Type::String,

View File

@ -18,6 +18,8 @@ pub struct Call {
pub arguments: Vec<Argument>, pub arguments: Vec<Argument>,
pub redirect_stdout: bool, pub redirect_stdout: bool,
pub redirect_stderr: bool, pub redirect_stderr: bool,
/// this field is used by the parser to pass additional command-specific information
pub parser_info: Vec<Expression>,
} }
impl Call { impl Call {
@ -28,6 +30,7 @@ impl Call {
arguments: vec![], arguments: vec![],
redirect_stdout: true, redirect_stdout: true,
redirect_stderr: false, redirect_stderr: false,
parser_info: vec![],
} }
} }
@ -67,6 +70,10 @@ impl Call {
self.arguments.push(Argument::Positional(positional)); self.arguments.push(Argument::Positional(positional));
} }
pub fn add_parser_info(&mut self, info: Expression) {
self.parser_info.push(info);
}
pub fn add_unknown(&mut self, unknown: Expression) { pub fn add_unknown(&mut self, unknown: Expression) {
self.arguments.push(Argument::Unknown(unknown)); self.arguments.push(Argument::Unknown(unknown));
} }
@ -99,6 +106,10 @@ impl Call {
self.positional_iter().count() self.positional_iter().count()
} }
pub fn parser_info_nth(&self, i: usize) -> Option<&Expression> {
self.parser_info.get(i)
}
pub fn has_flag(&self, flag_name: &str) -> bool { pub fn has_flag(&self, flag_name: &str) -> bool {
for name in self.named_iter() { for name in self.named_iter() {
if flag_name == name.0.item { if flag_name == name.0.item {