mirror of
https://github.com/nushell/nushell
synced 2024-12-27 05:23:11 +00: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
4 changed files with 18 additions and 12 deletions
|
@ -77,6 +77,10 @@ pub enum ParseError {
|
|||
#[diagnostic(code(nu::parser::module_not_found), url(docsrs))]
|
||||
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.")]
|
||||
#[diagnostic(
|
||||
code(nu::parser::unknown_command),
|
||||
|
|
|
@ -13,7 +13,7 @@ use crate::{
|
|||
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]);
|
||||
|
||||
// handle "export def" same as "def"
|
||||
|
@ -42,9 +42,13 @@ pub fn parse_def_predecl(working_set: &mut StateWorkingSet, spans: &[Span]) {
|
|||
signature.name = name;
|
||||
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(
|
||||
|
@ -98,7 +102,7 @@ pub fn parse_def(
|
|||
(&name, signature, block_id)
|
||||
{
|
||||
let decl_id = working_set
|
||||
.find_predecl(name.as_bytes())
|
||||
.find_decl(name.as_bytes())
|
||||
.expect("internal error: predeclaration failed to add definition");
|
||||
|
||||
let declaration = working_set.get_decl_mut(decl_id);
|
||||
|
|
|
@ -2606,16 +2606,18 @@ pub fn parse_block(
|
|||
working_set.enter_scope();
|
||||
}
|
||||
|
||||
let mut error = None;
|
||||
|
||||
// Pre-declare any definition so that definitions
|
||||
// that share the same block can see each other
|
||||
for pipeline in &lite_block.block {
|
||||
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
|
||||
.block
|
||||
.iter()
|
||||
|
|
|
@ -311,17 +311,13 @@ impl<'a> StateWorkingSet<'a> {
|
|||
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();
|
||||
|
||||
self.delta.decls.push(decl);
|
||||
let decl_id = self.num_decls() - 1;
|
||||
|
||||
self.delta.predecls.insert(name, decl_id);
|
||||
}
|
||||
|
||||
pub fn find_predecl(&mut self, name: &[u8]) -> Option<DeclId> {
|
||||
self.delta.predecls.get(name).copied()
|
||||
self.delta.predecls.insert(name, decl_id)
|
||||
}
|
||||
|
||||
pub fn merge_predecl(&mut self, name: &[u8]) -> Option<DeclId> {
|
||||
|
|
Loading…
Reference in a new issue