forked from extern/nushell
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>) {
|
pub fn parse_def(&mut self, spans: &[Span]) -> (Statement, Option<ParseError>) {
|
||||||
let mut error = None;
|
let mut error = None;
|
||||||
let name = self.get_span_contents(spans[0]);
|
let name = self.get_span_contents(spans[0]);
|
||||||
@ -2102,11 +2129,16 @@ impl<'a> ParserWorkingSet<'a> {
|
|||||||
.expect("internal error: expected def name");
|
.expect("internal error: expected def name");
|
||||||
error = error.or(err);
|
error = error.or(err);
|
||||||
|
|
||||||
|
let decl_id = self
|
||||||
|
.find_decl(name.as_bytes())
|
||||||
|
.expect("internal error: predeclaration failed to add definition");
|
||||||
|
|
||||||
self.enter_scope();
|
self.enter_scope();
|
||||||
let (sig, err) = self.parse_signature(spans[2]);
|
let (sig, err) = self.parse_signature(spans[2]);
|
||||||
let mut signature = sig
|
let mut signature = sig
|
||||||
.as_signature()
|
.as_signature()
|
||||||
.expect("internal error: expected param list");
|
.expect("internal error: expected param list");
|
||||||
|
signature.name = name;
|
||||||
error = error.or(err);
|
error = error.or(err);
|
||||||
|
|
||||||
let (block, err) = self.parse_block_expression(spans[3]);
|
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");
|
let block_id = block.as_block().expect("internal error: expected block");
|
||||||
error = error.or(err);
|
error = error.or(err);
|
||||||
|
|
||||||
signature.name = name;
|
let declaration = self.get_decl_mut(decl_id);
|
||||||
let decl = Declaration {
|
declaration.signature = signature;
|
||||||
signature,
|
declaration.body = Some(block_id);
|
||||||
body: Some(block_id),
|
|
||||||
};
|
|
||||||
|
|
||||||
self.add_decl(decl);
|
|
||||||
let def_decl_id = self
|
let def_decl_id = self
|
||||||
.find_decl(b"def")
|
.find_decl(b"def")
|
||||||
.expect("internal error: missing def command");
|
.expect("internal error: missing def command");
|
||||||
@ -2211,6 +2240,14 @@ impl<'a> ParserWorkingSet<'a> {
|
|||||||
|
|
||||||
let mut block = Block::new();
|
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 {
|
for pipeline in &lite_block.block {
|
||||||
if pipeline.commands.len() > 1 {
|
if pipeline.commands.len() > 1 {
|
||||||
let mut output = vec![];
|
let mut output = vec![];
|
||||||
|
@ -306,6 +306,11 @@ impl<'a> ParserWorkingSet<'a> {
|
|||||||
None
|
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 {
|
pub fn contains_decl_partial_match(&self, name: &[u8]) -> bool {
|
||||||
for scope in self.delta.scope.iter().rev() {
|
for scope in self.delta.scope.iter().rev() {
|
||||||
for decl in &scope.decls {
|
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 {
|
pub fn get_block(&self, block_id: BlockId) -> &Block {
|
||||||
let num_permanent_blocks = self.permanent_state.num_blocks();
|
let num_permanent_blocks = self.permanent_state.num_blocks();
|
||||||
if block_id < num_permanent_blocks {
|
if block_id < num_permanent_blocks {
|
||||||
|
13
src/tests.rs
13
src/tests.rs
@ -78,7 +78,7 @@ fn if_test2() -> TestResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn no_leak1() -> TestResult {
|
fn no_scope_leak1() -> TestResult {
|
||||||
fail_test(
|
fail_test(
|
||||||
"if $false { let $x = 10 } else { let $x = 20 }; $x",
|
"if $false { let $x = 10 } else { let $x = 20 }; $x",
|
||||||
"VariableNotFound",
|
"VariableNotFound",
|
||||||
@ -86,7 +86,7 @@ fn no_leak1() -> TestResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn no_leak2() -> TestResult {
|
fn no_scope_leak2() -> TestResult {
|
||||||
fail_test(
|
fail_test(
|
||||||
"def foo [] { $x }; def bar [] { let $x = 10; foo }; bar",
|
"def foo [] { $x }; def bar [] { let $x = 10; foo }; bar",
|
||||||
"VariableNotFound",
|
"VariableNotFound",
|
||||||
@ -94,7 +94,7 @@ fn no_leak2() -> TestResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn no_leak3() -> TestResult {
|
fn no_scope_leak3() -> TestResult {
|
||||||
run_test(
|
run_test(
|
||||||
"def foo [$x] { $x }; def bar [] { let $x = 10; foo 20}; bar",
|
"def foo [$x] { $x }; def bar [] { let $x = 10; foo 20}; bar",
|
||||||
"20",
|
"20",
|
||||||
@ -102,7 +102,7 @@ fn no_leak3() -> TestResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn no_leak4() -> TestResult {
|
fn no_scope_leak4() -> TestResult {
|
||||||
run_test(
|
run_test(
|
||||||
"def foo [$x] { $x }; def bar [] { let $x = 10; (foo 20) + $x}; bar",
|
"def foo [$x] { $x }; def bar [] { let $x = 10; (foo 20) + $x}; bar",
|
||||||
"30",
|
"30",
|
||||||
@ -113,3 +113,8 @@ fn no_leak4() -> TestResult {
|
|||||||
fn simple_var_closing() -> TestResult {
|
fn simple_var_closing() -> TestResult {
|
||||||
run_test("let $x = 10; def foo [] { $x }; foo", "10")
|
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