From 07de510d83f62e5fa10f9b801fe4f0ed943f9469 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Wed, 17 Feb 2021 21:01:00 +0100 Subject: remove unused field in block --- src/compiler.rs | 6 +++--- src/lib.rs | 4 +--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index 94ae2aa..6607c7f 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -719,10 +719,10 @@ impl Compiler { let mut args = Vec::new(); let mut return_type = Type::Void; - let mut function_block = Block::new(&name, &self.current_file, self.line()); + let mut function_block = Block::new(&name, &self.current_file); let block_id = self.blocks.len(); - let temp_block = Block::new(&name, &self.current_file, self.line()); + let temp_block = Block::new(&name, &self.current_file); self.blocks.push(Rc::new(RefCell::new(temp_block))); let _ret = push_frame!(self, function_block, { @@ -1389,7 +1389,7 @@ impl Compiler { mutable: true, }); - let mut block = Block::new(name, file, 0); + let mut block = Block::new(name, file); while self.peek() != Token::EOF { self.statement(&mut block); expect!(self, Token::Newline | Token::EOF, "Expect newline or EOF after expression."); diff --git a/src/lib.rs b/src/lib.rs index 77176c4..c940a88 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -635,11 +635,10 @@ pub struct Block { ops: Vec, last_line_offset: usize, line_offsets: HashMap, - line: usize, } impl Block { - fn new(name: &str, file: &Path, line: usize) -> Self { + fn new(name: &str, file: &Path) -> Self { Self { ty: Type::Void, upvalues: Vec::new(), @@ -648,7 +647,6 @@ impl Block { ops: Vec::new(), last_line_offset: 0, line_offsets: HashMap::new(), - line, } } -- cgit v1.2.1 From b205748bde51c551468a8dc89123f85b67c660dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Wed, 17 Feb 2021 21:01:12 +0100 Subject: solve edge case for constants --- src/compiler.rs | 13 ++++++++++--- src/lib.rs | 24 +++++++++++++++++++++--- src/vm.rs | 19 +++++++++++++------ 3 files changed, 44 insertions(+), 12 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index 6607c7f..c0dacec 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -914,12 +914,19 @@ impl Compiler { // Remove the function, since it's a constant and we already // added it. block.ops.pop().unwrap(); - if let Entry::Occupied(entry) = self.unknown.entry(String::from(name)) { + let slot = if let Entry::Occupied(entry) = self.unknown.entry(String::from(name)) { let (_, (slot, _)) = entry.remove_entry(); self.constants[slot] = self.constants.pop().unwrap(); - add_op(self, block, Op::Link(slot)); + slot } else { - add_op(self, block, Op::Link(self.constants.len() - 1)); + self.constants.len() - 1 + }; + add_op(self, block, Op::Link(slot)); + if let Value::Function(_, block) = &self.constants[slot] { + let needs_linking = block.borrow().upvalues.len() != 0; + block.borrow_mut().constant = needs_linking; + } else { + unreachable!(); } return; } diff --git a/src/lib.rs b/src/lib.rs index c940a88..1bdcc00 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -151,7 +151,7 @@ impl From<&Type> for Value { Type::String => Value::String(Rc::new("".to_string())), Type::Function(_, _) => Value::Function( Vec::new(), - Rc::new(RefCell::new(Block::empty_with_type(ty)))), + Rc::new(RefCell::new(Block::stubbed_block(ty)))), } } } @@ -635,6 +635,8 @@ pub struct Block { ops: Vec, last_line_offset: usize, line_offsets: HashMap, + linked: bool, + constant: bool, } impl Block { @@ -647,12 +649,14 @@ impl Block { ops: Vec::new(), last_line_offset: 0, line_offsets: HashMap::new(), + linked: false, + constant: false, } } // Used to create empty functions. - fn empty_with_type(ty: &Type) -> Self { - let mut block = Block::new("/empty/", Path::new(""), 0); + fn stubbed_block(ty: &Type) -> Self { + let mut block = Block::new("/empty/", Path::new("")); block.ty = ty.clone(); block } @@ -854,6 +858,20 @@ mod tests { assert_errs!(run_string("a :: B()\n", true, Vec::new()), [ErrorKind::SyntaxError(_, _)]); } + #[test] + fn call_before_link() { + let prog = " +a := 1 +f() +c := 5 + +f :: fn { + c <=> 5 +} + "; + assert_errs!(run_string(prog, true, Vec::new()), [ErrorKind::InvalidProgram, ErrorKind::RuntimeTypeError(_, _)]); + } + macro_rules! test_multiple { ($mod:ident, $( $fn:ident : $prog:literal ),+ $( , )? ) => { diff --git a/src/vm.rs b/src/vm.rs index f5c1cf0..20125be 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -557,6 +557,13 @@ impl VM { Value::Function(_, block) => { self.push(Value::Function(Vec::new(), block.clone())); + if block.borrow().constant && !block.borrow().linked { + error!(self, + ErrorKind::InvalidProgram, + format!("Calling function '{}' before all captured variables are declared.", + block.borrow().name)); + } + let mut types = Vec::new(); for (slot, is_up, ty) in block.borrow().upvalues.iter() { if *is_up { @@ -667,10 +674,10 @@ impl VM { } Op::Link(slot) => { - println!("{:?}", self.constants); - println!("{:?} - {}", self.constant(slot), slot); match self.constant(slot).clone() { - Value::Function(_, _) => {} + Value::Function(_, block) => { + block.borrow_mut().linked = true; + } value => { error!(self, ErrorKind::TypeError(op, vec![Type::from(&value)]), @@ -733,7 +740,7 @@ impl VM { } _ => { error!(self, - ErrorKind::TypeError(op, vec![Type::from(&self.stack[new_base])]), + ErrorKind::InvalidProgram, format!("Tried to call non-function {:?}", self.stack[new_base])); } } @@ -773,7 +780,7 @@ impl VM { }); if self.print_blocks { - println!("\n [[{}]]\n", "TYPECHECK".purple()); + println!("\n [[{} - {}]]\n", "TYPECHECKING".purple(), self.frame().block.borrow().name); self.frame().block.borrow().debug_print(); } @@ -832,7 +839,7 @@ mod tests { f := fn i: int { i() }", - [ErrorKind::TypeError(_, _)]); + [ErrorKind::InvalidProgram]); test_string!(wrong_params, " f : fn -> int = fn a: int -> int {}", -- cgit v1.2.1 From 090dd8c52e4ae60742fe8bad7b74e18bb808ba0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Wed, 17 Feb 2021 21:15:54 +0100 Subject: use enums instead of 2 bools --- src/compiler.rs | 3 +-- src/lib.rs | 29 +++++++++++++++++++++++++---- src/vm.rs | 4 ++-- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index c0dacec..c70640d 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -923,8 +923,7 @@ impl Compiler { }; add_op(self, block, Op::Link(slot)); if let Value::Function(_, block) = &self.constants[slot] { - let needs_linking = block.borrow().upvalues.len() != 0; - block.borrow_mut().constant = needs_linking; + block.borrow_mut().mark_constant(); } else { unreachable!(); } diff --git a/src/lib.rs b/src/lib.rs index 1bdcc00..42a74a0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -625,18 +625,24 @@ mod op { } } +#[derive(Debug)] +enum BlockLinkState { + Linked, + Unlinked, + Nothing, +} + #[derive(Debug)] pub struct Block { pub ty: Type, upvalues: Vec<(usize, bool, Type)>, + linking: BlockLinkState, pub name: String, pub file: PathBuf, ops: Vec, last_line_offset: usize, line_offsets: HashMap, - linked: bool, - constant: bool, } impl Block { @@ -644,16 +650,31 @@ impl Block { Self { ty: Type::Void, upvalues: Vec::new(), + linking: BlockLinkState::Nothing, + name: String::from(name), file: file.to_owned(), ops: Vec::new(), last_line_offset: 0, line_offsets: HashMap::new(), - linked: false, - constant: false, } } + fn mark_constant(&mut self) { + if self.upvalues.is_empty() { + return; + } + self.linking = BlockLinkState::Unlinked; + } + + fn link(&mut self) { + self.linking = BlockLinkState::Linked; + } + + fn needs_linking(&self) -> bool { + matches!(self.linking, BlockLinkState::Unlinked) + } + // Used to create empty functions. fn stubbed_block(ty: &Type) -> Self { let mut block = Block::new("/empty/", Path::new("")); diff --git a/src/vm.rs b/src/vm.rs index 20125be..5e7810d 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -557,7 +557,7 @@ impl VM { Value::Function(_, block) => { self.push(Value::Function(Vec::new(), block.clone())); - if block.borrow().constant && !block.borrow().linked { + if block.borrow().needs_linking() { error!(self, ErrorKind::InvalidProgram, format!("Calling function '{}' before all captured variables are declared.", @@ -676,7 +676,7 @@ impl VM { Op::Link(slot) => { match self.constant(slot).clone() { Value::Function(_, block) => { - block.borrow_mut().linked = true; + block.borrow_mut().link(); } value => { error!(self, -- cgit v1.2.1