mirror of
https://github.com/nushell/nushell.git
synced 2025-05-07 03:24:25 +02:00
Fix panic on double def; Tests; Double def error
* Fixes a panic with defining two commands with the same name caused by declaration not found after predeclaration. * Adds a new error if a custom command is defined more than once in one block. * Add some tests
This commit is contained in:
parent
2af8116f50
commit
25b05dec9e
@ -77,6 +77,10 @@ pub enum ParseError {
|
|||||||
#[diagnostic(code(nu::parser::module_not_found), url(docsrs))]
|
#[diagnostic(code(nu::parser::module_not_found), url(docsrs))]
|
||||||
ModuleNotFound(#[label = "module not found"] Span),
|
ModuleNotFound(#[label = "module not found"] Span),
|
||||||
|
|
||||||
|
#[error("Duplicate command definition within a block.")]
|
||||||
|
#[diagnostic(code(nu::parser::duplicate_command_def), url(docsrs))]
|
||||||
|
DuplicateCommandDef(#[label = "defined more than once"] Span),
|
||||||
|
|
||||||
#[error("Unknown command.")]
|
#[error("Unknown command.")]
|
||||||
#[diagnostic(
|
#[diagnostic(
|
||||||
code(nu::parser::unknown_command),
|
code(nu::parser::unknown_command),
|
||||||
|
@ -13,7 +13,7 @@ use crate::{
|
|||||||
ParseError,
|
ParseError,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn parse_def_predecl(working_set: &mut StateWorkingSet, spans: &[Span]) {
|
pub fn parse_def_predecl(working_set: &mut StateWorkingSet, spans: &[Span]) -> Option<ParseError> {
|
||||||
let name = working_set.get_span_contents(spans[0]);
|
let name = working_set.get_span_contents(spans[0]);
|
||||||
|
|
||||||
// handle "export def" same as "def"
|
// handle "export def" same as "def"
|
||||||
@ -42,9 +42,13 @@ pub fn parse_def_predecl(working_set: &mut StateWorkingSet, spans: &[Span]) {
|
|||||||
signature.name = name;
|
signature.name = name;
|
||||||
let decl = signature.predeclare();
|
let decl = signature.predeclare();
|
||||||
|
|
||||||
working_set.add_predecl(decl);
|
if working_set.add_predecl(decl).is_some() {
|
||||||
|
return Some(ParseError::DuplicateCommandDef(spans[1]));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_def(
|
pub fn parse_def(
|
||||||
@ -98,7 +102,7 @@ pub fn parse_def(
|
|||||||
(&name, signature, block_id)
|
(&name, signature, block_id)
|
||||||
{
|
{
|
||||||
let decl_id = working_set
|
let decl_id = working_set
|
||||||
.find_predecl(name.as_bytes())
|
.find_decl(name.as_bytes())
|
||||||
.expect("internal error: predeclaration failed to add definition");
|
.expect("internal error: predeclaration failed to add definition");
|
||||||
|
|
||||||
let declaration = working_set.get_decl_mut(decl_id);
|
let declaration = working_set.get_decl_mut(decl_id);
|
||||||
|
@ -2606,16 +2606,18 @@ pub fn parse_block(
|
|||||||
working_set.enter_scope();
|
working_set.enter_scope();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut error = None;
|
||||||
|
|
||||||
// Pre-declare any definition so that definitions
|
// Pre-declare any definition so that definitions
|
||||||
// that share the same block can see each other
|
// that share the same block can see each other
|
||||||
for pipeline in &lite_block.block {
|
for pipeline in &lite_block.block {
|
||||||
if pipeline.commands.len() == 1 {
|
if pipeline.commands.len() == 1 {
|
||||||
parse_def_predecl(working_set, &pipeline.commands[0].parts);
|
if let Some(err) = parse_def_predecl(working_set, &pipeline.commands[0].parts) {
|
||||||
|
error = error.or(Some(err));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut error = None;
|
|
||||||
|
|
||||||
let block: Block = lite_block
|
let block: Block = lite_block
|
||||||
.block
|
.block
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -311,17 +311,13 @@ impl<'a> StateWorkingSet<'a> {
|
|||||||
decl_id
|
decl_id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_predecl(&mut self, decl: Box<dyn Command>) {
|
pub fn add_predecl(&mut self, decl: Box<dyn Command>) -> Option<DeclId> {
|
||||||
let name = decl.name().as_bytes().to_vec();
|
let name = decl.name().as_bytes().to_vec();
|
||||||
|
|
||||||
self.delta.decls.push(decl);
|
self.delta.decls.push(decl);
|
||||||
let decl_id = self.num_decls() - 1;
|
let decl_id = self.num_decls() - 1;
|
||||||
|
|
||||||
self.delta.predecls.insert(name, decl_id);
|
self.delta.predecls.insert(name, decl_id)
|
||||||
}
|
|
||||||
|
|
||||||
pub fn find_predecl(&mut self, name: &[u8]) -> Option<DeclId> {
|
|
||||||
self.delta.predecls.get(name).copied()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn merge_predecl(&mut self, name: &[u8]) -> Option<DeclId> {
|
pub fn merge_predecl(&mut self, name: &[u8]) -> Option<DeclId> {
|
||||||
|
Loading…
Reference in New Issue
Block a user