Implement a rough version of 'hide'

'hide' command is used to undefine custom commands
This commit is contained in:
Jakub Žádník 2021-09-28 23:18:48 +03:00
parent 3cbf99053f
commit 7488254cca
5 changed files with 150 additions and 13 deletions

View file

@ -14,7 +14,7 @@ impl Command for Use {
}
fn signature(&self) -> nu_protocol::Signature {
Signature::build("use").required("module_name", SyntaxShape::String, "module name")
Signature::build("use").required("pattern", SyntaxShape::String, "import pattern")
}
fn run(

View file

@ -7,7 +7,7 @@ use nu_protocol::{
use crate::{
Alias, Benchmark, BuildString, Def, Do, Each, ExportDef, External, For, From, FromJson, Git, GitCheckout,
If, Length, Let, LetEnv, Lines, ListGitBranches, Ls, Module, Sys, Table, Use, Where,
Hide, If, Length, Let, LetEnv, Lines, ListGitBranches, Ls, Module, Sys, Table, Use, Where,
};
pub fn create_default_context() -> Rc<RefCell<EngineState>> {
@ -29,8 +29,8 @@ pub fn create_default_context() -> Rc<RefCell<EngineState>> {
working_set.add_decl(Box::new(Alias));
working_set.add_decl(Box::new(Benchmark));
working_set.add_decl(Box::new(BuildString));
working_set.add_decl(Box::new(Def));
working_set.add_decl(Box::new(Def));
working_set.add_decl(Box::new(Do));
working_set.add_decl(Box::new(Each));
working_set.add_decl(Box::new(ExportDef));
@ -38,6 +38,7 @@ pub fn create_default_context() -> Rc<RefCell<EngineState>> {
working_set.add_decl(Box::new(For));
working_set.add_decl(Box::new(From));
working_set.add_decl(Box::new(FromJson));
working_set.add_decl(Box::new(Hide));
working_set.add_decl(Box::new(If));
working_set.add_decl(Box::new(Length));
working_set.add_decl(Box::new(Let));
@ -48,7 +49,7 @@ pub fn create_default_context() -> Rc<RefCell<EngineState>> {
working_set.add_decl(Box::new(Sys));
working_set.add_decl(Box::new(Table));
working_set.add_decl(Box::new(Use));
working_set.add_decl(Box::new(Where));
working_set.add_decl(Box::new(Where));
// This is a WIP proof of concept
working_set.add_decl(Box::new(ListGitBranches));

View file

@ -472,8 +472,6 @@ pub fn parse_use(
let mut error = None;
let bytes = working_set.get_span_contents(spans[0]);
// TODO: Currently, this directly imports the module's definitions into the current scope.
// Later, we want to put them behind the module's name and add selective importing
if bytes == b"use" && spans.len() >= 2 {
let (module_name_expr, err) = parse_string(working_set, spans[1]);
error = error.or(err);
@ -482,8 +480,6 @@ pub fn parse_use(
error = error.or(err);
let exports = if let Some(block_id) = working_set.find_module(&import_pattern.head) {
// TODO: Since we don't use the Block at all, we might just as well create a separate
// Module that holds only the exports, without having Blocks in the way.
working_set.get_block(block_id).exports.clone()
} else {
return (
@ -571,6 +567,65 @@ pub fn parse_use(
}
}
pub fn parse_hide(
working_set: &mut StateWorkingSet,
spans: &[Span],
) -> (Statement, Option<ParseError>) {
let mut error = None;
let bytes = working_set.get_span_contents(spans[0]);
if bytes == b"hide" && spans.len() >= 2 {
let (name_expr, err) = parse_string(working_set, spans[1]);
error = error.or(err);
let name_bytes: Vec<u8> = working_set.get_span_contents(spans[1]).into();
// TODO: Do the import pattern stuff for bulk-hiding
// TODO: move this error into error = error.or pattern
let _decl_id = if let Some(id) = working_set.find_decl(&name_bytes) {
id
} else {
return (
garbage_statement(spans),
Some(ParseError::UnknownCommand(spans[1])),
);
};
// Hide the definitions
working_set.hide_decl(name_bytes);
// Create the Hide command call
let hide_decl_id = working_set
.find_decl(b"hide")
.expect("internal error: missing hide command");
let call = Box::new(Call {
head: spans[0],
decl_id: hide_decl_id,
positional: vec![name_expr],
named: vec![],
});
(
Statement::Pipeline(Pipeline::from_vec(vec![Expression {
expr: Expr::Call(call),
span: span(spans),
ty: Type::Unknown,
custom_completion: None,
}])),
error,
)
} else {
(
garbage_statement(spans),
Some(ParseError::UnknownState(
"Expected structure: hide <name>".into(),
span(spans),
)),
)
}
}
pub fn parse_let(
working_set: &mut StateWorkingSet,
spans: &[Span],

View file

@ -14,7 +14,7 @@ use nu_protocol::{
};
use crate::parse_keywords::{
parse_alias, parse_def, parse_def_predecl, parse_let, parse_module, parse_use,
parse_alias, parse_def, parse_def_predecl, parse_hide, parse_let, parse_module, parse_use,
};
#[derive(Debug, Clone)]
@ -2589,6 +2589,7 @@ pub fn parse_statement(
garbage_statement(spans),
Some(ParseError::UnexpectedKeyword("export".into(), spans[0])),
),
b"hide" => parse_hide(working_set, spans),
_ => {
let (expr, err) = parse_expression(working_set, spans);
(Statement::Pipeline(Pipeline::from_vec(vec![expr])), err)

View file

@ -18,6 +18,7 @@ pub struct ScopeFrame {
decls: HashMap<Vec<u8>, DeclId>,
aliases: HashMap<Vec<u8>, Vec<Span>>,
modules: HashMap<Vec<u8>, BlockId>,
hiding: HashMap<Vec<u8>, usize>, // defines what is being hidden and its "hiding strength"
}
impl ScopeFrame {
@ -27,6 +28,7 @@ impl ScopeFrame {
decls: HashMap::new(),
aliases: HashMap::new(),
modules: HashMap::new(),
hiding: HashMap::new(),
}
}
@ -81,6 +83,9 @@ impl EngineState {
for item in first.modules.into_iter() {
last.modules.insert(item.0, item.1);
}
for item in first.hiding.into_iter() {
last.hiding.insert(item.0, item.1);
}
}
}
@ -124,9 +129,23 @@ impl EngineState {
}
pub fn find_decl(&self, name: &[u8]) -> Option<DeclId> {
let mut hiding_strength = 0;
// println!("state: starting finding {}", String::from_utf8_lossy(&name));
for scope in self.scope.iter().rev() {
// println!("hiding map: {:?}", scope.hiding);
// check if we're hiding the declin this scope
if let Some(strength) = scope.hiding.get(name) {
hiding_strength += strength;
}
if let Some(decl_id) = scope.decls.get(name) {
return Some(*decl_id);
// if we're hiding this decl, do not return it and reduce the hiding strength
if hiding_strength > 0 {
hiding_strength -= 1;
} else {
return Some(*decl_id);
}
}
}
@ -243,10 +262,12 @@ impl StateDelta {
}
pub fn enter_scope(&mut self) {
// println!("enter scope");
self.scope.push(ScopeFrame::new());
}
pub fn exit_scope(&mut self) {
// println!("exit scope");
self.scope.pop();
}
}
@ -280,6 +301,7 @@ impl<'a> StateWorkingSet<'a> {
pub fn add_decl(&mut self, decl: Box<dyn Command>) -> DeclId {
let name = decl.name().as_bytes().to_vec();
// println!("adding {}", String::from_utf8_lossy(&name));
self.delta.decls.push(decl);
let decl_id = self.num_decls() - 1;
@ -289,11 +311,36 @@ impl<'a> StateWorkingSet<'a> {
.scope
.last_mut()
.expect("internal error: missing required scope frame");
// reset "hiding strength" to 0 => not hidden
if let Some(strength) = scope_frame.hiding.get_mut(&name) {
*strength = 0;
// println!(" strength: {}", strength);
}
scope_frame.decls.insert(name, decl_id);
decl_id
}
pub fn hide_decl(&mut self, name: Vec<u8>) {
let scope_frame = self
.delta
.scope
.last_mut()
.expect("internal error: missing required scope frame");
if let Some(strength) = scope_frame.hiding.get_mut(&name) {
*strength += 1;
// println!("hiding {}, strength: {}", String::from_utf8_lossy(&name), strength);
} else {
// println!("hiding {}, strength: 1", String::from_utf8_lossy(&name));
scope_frame.hiding.insert(name, 1);
}
// println!("hiding map: {:?}", scope_frame.hiding);
}
pub fn add_block(&mut self, block: Block) -> BlockId {
self.delta.blocks.push(block);
@ -401,15 +448,48 @@ impl<'a> StateWorkingSet<'a> {
}
pub fn find_decl(&self, name: &[u8]) -> Option<DeclId> {
let mut hiding_strength = 0;
// println!("set: starting finding {}", String::from_utf8_lossy(&name));
for scope in self.delta.scope.iter().rev() {
// println!("delta frame");
// println!("hiding map: {:?}", scope.hiding);
// check if we're hiding the declin this scope
if let Some(strength) = scope.hiding.get(name) {
hiding_strength += strength;
// println!(" was hiding, strength {}", hiding_strength);
}
if let Some(decl_id) = scope.decls.get(name) {
return Some(*decl_id);
// if we're hiding this decl, do not return it and reduce the hiding strength
if hiding_strength > 0 {
hiding_strength -= 1;
// println!(" decl found, strength {}", hiding_strength);
} else {
// println!(" decl found, return");
return Some(*decl_id);
}
}
}
for scope in self.permanent_state.scope.iter().rev() {
// println!("perma frame");
// println!("hiding map: {:?}", scope.hiding);
// check if we're hiding the declin this scope
if let Some(strength) = scope.hiding.get(name) {
hiding_strength += strength;
// println!(" was hiding, strength {}", hiding_strength);
}
if let Some(decl_id) = scope.decls.get(name) {
return Some(*decl_id);
// if we're hiding this decl, do not return it and reduce the hiding strength
if hiding_strength > 0 {
hiding_strength -= 1;
// println!(" decl found, strength {}", hiding_strength);
} else {
// println!(" decl found, return");
return Some(*decl_id);
}
}
}