Start parsing 'use'; Add Use command

This commit is contained in:
Jakub Žádník 2021-09-26 13:25:52 +03:00
parent 57a07385ac
commit 9e176674a5
6 changed files with 117 additions and 1 deletions

View File

@ -7,7 +7,7 @@ use nu_protocol::{
use crate::{
where_::Where, Alias, Benchmark, BuildString, Def, Do, Each, External, For, Git, GitCheckout,
If, Length, Let, LetEnv, Lines, ListGitBranches, Ls, Module, Table,
If, Length, Let, LetEnv, Lines, ListGitBranches, Ls, Module, Table, Use,
};
pub fn create_default_context() -> Rc<RefCell<EngineState>> {
@ -48,6 +48,8 @@ pub fn create_default_context() -> Rc<RefCell<EngineState>> {
working_set.add_decl(Box::new(Module));
working_set.add_decl(Box::new(Use));
working_set.add_decl(Box::new(Table));
working_set.add_decl(Box::new(External));

View File

@ -18,6 +18,7 @@ mod ls;
mod module;
mod run_external;
mod table;
mod use_;
mod where_;
pub use alias::Alias;
@ -40,3 +41,4 @@ pub use ls::Ls;
pub use module::Module;
pub use run_external::External;
pub use table::Table;
pub use use_::Use;

View File

@ -0,0 +1,29 @@
use nu_protocol::ast::Call;
use nu_protocol::engine::{Command, EvaluationContext};
use nu_protocol::{Signature, SyntaxShape, Value};
pub struct Use;
impl Command for Use {
fn name(&self) -> &str {
"use"
}
fn usage(&self) -> &str {
"Use definitions from a module"
}
fn signature(&self) -> nu_protocol::Signature {
Signature::build("use")
.required("module_name", SyntaxShape::String, "module name")
}
fn run(
&self,
_context: &EvaluationContext,
call: &Call,
_input: Value,
) -> Result<nu_protocol::Value, nu_protocol::ShellError> {
Ok(Value::Nothing { span: call.head })
}
}

View File

@ -65,6 +65,10 @@ pub enum ParseError {
#[diagnostic(code(nu::parser::variable_not_found), url(docsrs))]
VariableNotFound(#[label = "variable not found"] Span),
#[error("Module not found.")]
#[diagnostic(code(nu::parser::module_not_found), url(docsrs))]
ModuleNotFound(#[label = "module not found"] Span),
#[error("Unknown command.")]
#[diagnostic(
code(nu::parser::unknown_command),

View File

@ -2806,6 +2806,65 @@ pub fn parse_module(
}
}
pub fn parse_use(
working_set: &mut StateWorkingSet,
spans: &[Span],
) -> (Statement, Option<ParseError>) {
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);
let module_name = module_name_expr
.as_string()
.expect("internal error: module name is not a string");
let module_name_bytes = module_name.as_bytes().to_vec();
let block = if let Some(block_id) = working_set.find_module(&module_name_bytes) {
working_set.get_block(block_id)
} else {
return (
garbage_statement(spans),
Some(ParseError::ModuleNotFound(spans[1])),
);
};
let use_decl_id = working_set
.find_decl(b"use")
.expect("internal error: missing use command");
let call = Box::new(Call {
head: spans[0],
decl_id: use_decl_id,
positional: vec![module_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: use <name>".into(),
span(spans),
)),
)
}
}
pub fn parse_let(
working_set: &mut StateWorkingSet,
spans: &[Span],
@ -2865,6 +2924,7 @@ pub fn parse_statement(
b"let" => parse_let(working_set, spans),
b"alias" => parse_alias(working_set, spans),
b"module" => parse_module(working_set, spans),
b"use" => parse_use(working_set, spans),
_ => {
let (expr, err) = parse_expression(working_set, spans);
(Statement::Pipeline(Pipeline::from_vec(vec![expr])), err)

View File

@ -78,6 +78,9 @@ impl EngineState {
for item in first.aliases.into_iter() {
last.aliases.insert(item.0, item.1);
}
for item in first.modules.into_iter() {
last.modules.insert(item.0, item.1);
}
}
}
@ -394,6 +397,22 @@ impl<'a> StateWorkingSet<'a> {
None
}
pub fn find_module(&self, name: &[u8]) -> Option<BlockId> {
for scope in self.delta.scope.iter().rev() {
if let Some(block_id) = scope.modules.get(name) {
return Some(*block_id);
}
}
for scope in self.permanent_state.scope.iter().rev() {
if let Some(block_id) = scope.modules.get(name) {
return Some(*block_id);
}
}
None
}
// pub fn update_decl(&mut self, decl_id: usize, block: Option<BlockId>) {
// let decl = self.get_decl_mut(decl_id);
// decl.body = block;