From c2be740ad4f06c7be3c395340f140ad440f924f7 Mon Sep 17 00:00:00 2001 From: JT Date: Sat, 31 Jul 2021 16:04:42 +1200 Subject: [PATCH] def predecl --- src/parser.rs | 49 +++++++++++++++++++++++++++++++++++++++------ src/parser_state.rs | 17 ++++++++++++++++ src/tests.rs | 13 ++++++++---- 3 files changed, 69 insertions(+), 10 deletions(-) diff --git a/src/parser.rs b/src/parser.rs index b3217a9dc4..6913328878 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -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) { 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![]; diff --git a/src/parser_state.rs b/src/parser_state.rs index 72c19cb754..6ed8d98b29 100644 --- a/src/parser_state.rs +++ b/src/parser_state.rs @@ -306,6 +306,11 @@ impl<'a> ParserWorkingSet<'a> { None } + pub fn update_decl(&mut self, decl_id: usize, block: Option) { + 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 { diff --git a/src/tests.rs b/src/tests.rs index 2cdd1d77dc..22028ce3e2 100644 --- a/src/tests.rs +++ b/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") +}