Allow adding definitions from module into scope

This commit is contained in:
Jakub Žádník 2021-09-26 13:53:52 +03:00
parent 9e176674a5
commit f57f7b2def
3 changed files with 37 additions and 9 deletions

View File

@ -10,7 +10,7 @@ use nu_protocol::{
RangeInclusion, RangeOperator, Statement, RangeInclusion, RangeOperator, Statement,
}, },
engine::StateWorkingSet, engine::StateWorkingSet,
span, Flag, PositionalArg, Signature, Span, SyntaxShape, Type, VarId, span, DeclId, Flag, PositionalArg, Signature, Span, SyntaxShape, Type, VarId,
}; };
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -2653,6 +2653,9 @@ pub fn parse_module(
working_set: &mut StateWorkingSet, working_set: &mut StateWorkingSet,
spans: &[Span], spans: &[Span],
) -> (Statement, Option<ParseError>) { ) -> (Statement, Option<ParseError>) {
// TODO: Currently, module is closing over its parent scope (i.e., defs in the parent scope are
// visible and usable in this module's scope). We might want to disable that. How?
let mut error = None; let mut error = None;
let bytes = working_set.get_span_contents(spans[0]); let bytes = working_set.get_span_contents(spans[0]);
@ -2719,7 +2722,7 @@ pub fn parse_module(
} }
} }
let mut exports: Vec<Vec<u8>> = vec![]; let mut exports: Vec<(Vec<u8>, DeclId)> = vec![];
let block: Block = output let block: Block = output
.block .block
@ -2736,10 +2739,15 @@ pub fn parse_module(
let (stmt, err) = parse_def(working_set, &pipeline.commands[0].parts); let (stmt, err) = parse_def(working_set, &pipeline.commands[0].parts);
if err.is_none() { if err.is_none() {
let def_name = let decl_name =
working_set.get_span_contents(pipeline.commands[0].parts[1]); working_set.get_span_contents(pipeline.commands[0].parts[1]);
let decl_id = working_set
.find_decl(decl_name)
.expect("internal error: failed to find added declaration");
// TODO: Later, we want to put this behind 'export' // TODO: Later, we want to put this behind 'export'
exports.push(def_name.into()); exports.push((decl_name.into(), decl_id));
} }
(stmt, err) (stmt, err)
@ -2825,8 +2833,10 @@ pub fn parse_use(
let module_name_bytes = module_name.as_bytes().to_vec(); let module_name_bytes = module_name.as_bytes().to_vec();
let block = if let Some(block_id) = working_set.find_module(&module_name_bytes) { let exports = if let Some(block_id) = working_set.find_module(&module_name_bytes) {
working_set.get_block(block_id) // 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 { } else {
return ( return (
garbage_statement(spans), garbage_statement(spans),
@ -2834,6 +2844,10 @@ pub fn parse_use(
); );
}; };
// Extend the current scope with the module's exports
working_set.activate_overlay(exports);
// Create the Use command call
let use_decl_id = working_set let use_decl_id = working_set
.find_decl(b"use") .find_decl(b"use")
.expect("internal error: missing use command"); .expect("internal error: missing use command");

View File

@ -1,6 +1,6 @@
use std::ops::{Index, IndexMut}; use std::ops::{Index, IndexMut};
use crate::Signature; use crate::{Signature, DeclId};
use super::Statement; use super::Statement;
@ -8,7 +8,7 @@ use super::Statement;
pub struct Block { pub struct Block {
pub signature: Box<Signature>, pub signature: Box<Signature>,
pub stmts: Vec<Statement>, pub stmts: Vec<Statement>,
pub exports: Vec<Vec<u8>>, // Assuming just defs for now pub exports: Vec<(Vec<u8>, DeclId)>, // Assuming just defs for now
} }
impl Block { impl Block {
@ -50,7 +50,7 @@ impl Block {
} }
} }
pub fn with_exports(self, exports: Vec<Vec<u8>>) -> Self { pub fn with_exports(self, exports: Vec<(Vec<u8>, DeclId)>) -> Self {
Self { Self {
signature: self.signature, signature: self.signature,
stmts: self.stmts, stmts: self.stmts,

View File

@ -312,6 +312,20 @@ impl<'a> StateWorkingSet<'a> {
block_id block_id
} }
pub fn activate_overlay(&mut self, overlay: Vec<(Vec<u8>, DeclId)>) {
// TODO: This will overwrite all existing definitions in a scope. When we add deactivate,
// we need to re-think how make it recoverable.
let scope_frame = self
.delta
.scope
.last_mut()
.expect("internal error: missing required scope frame");
for (name, decl_id) in overlay {
scope_frame.decls.insert(name, decl_id);
}
}
pub fn next_span_start(&self) -> usize { pub fn next_span_start(&self) -> usize {
self.permanent_state.next_span_start() + self.delta.file_contents.len() self.permanent_state.next_span_start() + self.delta.file_contents.len()
} }