mirror of
https://github.com/nushell/nushell.git
synced 2024-11-07 17:14:23 +01:00
def predecl
This commit is contained in:
parent
61258d03ad
commit
c2be740ad4
@ -2090,6 +2090,33 @@ impl<'a> ParserWorkingSet<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_def_predecl(&mut self, spans: &[Span]) {
|
||||
let name = self.get_span_contents(spans[0]);
|
||||
|
||||
if name == b"def" && spans.len() >= 4 {
|
||||
//FIXME: don't use expect here
|
||||
let (name_expr, ..) = self.parse_string(spans[1]);
|
||||
let name = name_expr
|
||||
.as_string()
|
||||
.expect("internal error: expected def name");
|
||||
|
||||
self.enter_scope();
|
||||
let (sig, ..) = self.parse_signature(spans[2]);
|
||||
let mut signature = sig
|
||||
.as_signature()
|
||||
.expect("internal error: expected param list");
|
||||
self.exit_scope();
|
||||
|
||||
signature.name = name;
|
||||
let decl = Declaration {
|
||||
signature,
|
||||
body: None,
|
||||
};
|
||||
|
||||
self.add_decl(decl);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_def(&mut self, spans: &[Span]) -> (Statement, Option<ParseError>) {
|
||||
let mut error = None;
|
||||
let name = self.get_span_contents(spans[0]);
|
||||
@ -2102,11 +2129,16 @@ impl<'a> ParserWorkingSet<'a> {
|
||||
.expect("internal error: expected def name");
|
||||
error = error.or(err);
|
||||
|
||||
let decl_id = self
|
||||
.find_decl(name.as_bytes())
|
||||
.expect("internal error: predeclaration failed to add definition");
|
||||
|
||||
self.enter_scope();
|
||||
let (sig, err) = self.parse_signature(spans[2]);
|
||||
let mut signature = sig
|
||||
.as_signature()
|
||||
.expect("internal error: expected param list");
|
||||
signature.name = name;
|
||||
error = error.or(err);
|
||||
|
||||
let (block, err) = self.parse_block_expression(spans[3]);
|
||||
@ -2115,13 +2147,10 @@ impl<'a> ParserWorkingSet<'a> {
|
||||
let block_id = block.as_block().expect("internal error: expected block");
|
||||
error = error.or(err);
|
||||
|
||||
signature.name = name;
|
||||
let decl = Declaration {
|
||||
signature,
|
||||
body: Some(block_id),
|
||||
};
|
||||
let declaration = self.get_decl_mut(decl_id);
|
||||
declaration.signature = signature;
|
||||
declaration.body = Some(block_id);
|
||||
|
||||
self.add_decl(decl);
|
||||
let def_decl_id = self
|
||||
.find_decl(b"def")
|
||||
.expect("internal error: missing def command");
|
||||
@ -2211,6 +2240,14 @@ impl<'a> ParserWorkingSet<'a> {
|
||||
|
||||
let mut block = Block::new();
|
||||
|
||||
// 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 {
|
||||
self.parse_def_predecl(&pipeline.commands[0].parts);
|
||||
}
|
||||
}
|
||||
|
||||
for pipeline in &lite_block.block {
|
||||
if pipeline.commands.len() > 1 {
|
||||
let mut output = vec![];
|
||||
|
@ -306,6 +306,11 @@ impl<'a> ParserWorkingSet<'a> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn update_decl(&mut self, decl_id: usize, block: Option<BlockId>) {
|
||||
let decl = self.get_decl_mut(decl_id);
|
||||
decl.body = block;
|
||||
}
|
||||
|
||||
pub fn contains_decl_partial_match(&self, name: &[u8]) -> bool {
|
||||
for scope in self.delta.scope.iter().rev() {
|
||||
for decl in &scope.decls {
|
||||
@ -401,6 +406,18 @@ impl<'a> ParserWorkingSet<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_decl_mut(&mut self, decl_id: DeclId) -> &mut Declaration {
|
||||
let num_permanent_decls = self.permanent_state.num_decls();
|
||||
if decl_id < num_permanent_decls {
|
||||
panic!("internal error: can only mutate declarations in working set")
|
||||
} else {
|
||||
self.delta
|
||||
.decls
|
||||
.get_mut(decl_id - num_permanent_decls)
|
||||
.expect("internal error: missing declaration")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_block(&self, block_id: BlockId) -> &Block {
|
||||
let num_permanent_blocks = self.permanent_state.num_blocks();
|
||||
if block_id < num_permanent_blocks {
|
||||
|
13
src/tests.rs
13
src/tests.rs
@ -78,7 +78,7 @@ fn if_test2() -> TestResult {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_leak1() -> TestResult {
|
||||
fn no_scope_leak1() -> TestResult {
|
||||
fail_test(
|
||||
"if $false { let $x = 10 } else { let $x = 20 }; $x",
|
||||
"VariableNotFound",
|
||||
@ -86,7 +86,7 @@ fn no_leak1() -> TestResult {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_leak2() -> TestResult {
|
||||
fn no_scope_leak2() -> TestResult {
|
||||
fail_test(
|
||||
"def foo [] { $x }; def bar [] { let $x = 10; foo }; bar",
|
||||
"VariableNotFound",
|
||||
@ -94,7 +94,7 @@ fn no_leak2() -> TestResult {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_leak3() -> TestResult {
|
||||
fn no_scope_leak3() -> TestResult {
|
||||
run_test(
|
||||
"def foo [$x] { $x }; def bar [] { let $x = 10; foo 20}; bar",
|
||||
"20",
|
||||
@ -102,7 +102,7 @@ fn no_leak3() -> TestResult {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_leak4() -> TestResult {
|
||||
fn no_scope_leak4() -> TestResult {
|
||||
run_test(
|
||||
"def foo [$x] { $x }; def bar [] { let $x = 10; (foo 20) + $x}; bar",
|
||||
"30",
|
||||
@ -113,3 +113,8 @@ fn no_leak4() -> TestResult {
|
||||
fn simple_var_closing() -> TestResult {
|
||||
run_test("let $x = 10; def foo [] { $x }; foo", "10")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn predecl_check() -> TestResult {
|
||||
run_test("def bob [] { sam }; def sam [] { 3 }; bob", "3")
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user