From d200cad16a3582d80855b379d55fd759995c4444 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Mon, 18 Jan 2021 22:16:19 +0100 Subject: big think, no progress --- src/compiler.rs | 40 ++++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) (limited to 'src/compiler.rs') diff --git a/src/compiler.rs b/src/compiler.rs index 1a6cfc6..ecd0180 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -104,14 +104,33 @@ struct Variable { typ: Type, scope: usize, active: bool, + upvalue: bool, } struct Frame { stack: Vec, + upvalues: Vec<(usize, Variable, bool)>, scope: usize, variables_below: usize, } +impl Frame { + fn find_local(&self, name: &str) -> Option<(usize, Type, usize, bool)> { + for (slot, var) in self.stack.iter().enumerate().rev() { + if var.name == name && var.active { + return Some((slot, var.typ.clone(), var.scope, false)); + } + } + None + } + + fn find_upvalue(&self, name: &str) -> Option<(usize, Type, usize, bool)> { + for (slot, upvalue) in self.upvalues.iter().enumerate() { + //TODO ?? + } + } +} + struct Compiler { curr: usize, tokens: TokenStream, @@ -388,11 +407,18 @@ impl Compiler { } } - fn find_local(&self, name: &str, _block: &Block) -> Option<(usize, Type, usize)> { - let frame = self.frame(); - for (slot, var) in frame.stack.iter().enumerate().rev() { - if var.name == name && var.active { - return Some((slot, var.typ.clone(), var.scope)); + fn find_upvalue(&self, name: &str, start_at: usize) -> Option<(usize, Type, usize, bool)> { + + } + + fn find_variable(&mut self, name: &str, mut iterator: I) -> Option<(usize, Type, usize, bool)> + where I: Iterator { + if let Some(frame) = i.next() { + if let Some(res) = frame.find_local(name) { + return Some(res); + } + if let Some(res) = frame.find_upvalue(name) { + return Some(res); } } None @@ -519,7 +545,8 @@ impl Compiler { name: String::from(name), typ, scope, - active: false + active: false, + upvalue: false, }); Ok(slot) } @@ -749,6 +776,7 @@ impl Compiler { typ: Type::Void, scope: 0, active: false, + upvalue: false, }); let mut block = Block::new(name, file, 0); -- cgit v1.2.1 From 85411e444826fc239fb268da03572993d9c9fd83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Wed, 20 Jan 2021 21:04:18 +0100 Subject: Add in upvalues --- src/compiler.rs | 112 +++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 87 insertions(+), 25 deletions(-) (limited to 'src/compiler.rs') diff --git a/src/compiler.rs b/src/compiler.rs index ecd0180..c4afbf3 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -79,7 +79,7 @@ impl From<&Value> for Type { Value::Float(_) => Type::Float, Value::Bool(_) => Type::Bool, Value::String(_) => Type::String, - Value::Function(block) => block.ty.clone(), + Value::Function(_, block) => block.ty.clone(), _ => Type::Void, } } @@ -94,40 +94,64 @@ impl Type { Type::Float => Value::Float(1.0), Type::Bool => Value::Bool(true), Type::String => Value::String(Rc::new("".to_string())), - Type::Function(_, _) => Value::Function(Rc::new(Block::from_type(self))), + Type::Function(_, _) => Value::Function( + Vec::new(), + Rc::new(Block::from_type(self))), } } } +#[derive(Clone)] struct Variable { name: String, typ: Type, scope: usize, + slot: usize, + outer_slot: usize, active: bool, upvalue: bool, + captured: bool, } struct Frame { stack: Vec, - upvalues: Vec<(usize, Variable, bool)>, + upvalues: Vec, scope: usize, variables_below: usize, } impl Frame { - fn find_local(&self, name: &str) -> Option<(usize, Type, usize, bool)> { - for (slot, var) in self.stack.iter().enumerate().rev() { + fn find_local(&self, name: &str) -> Option { + println!("LOCAL!"); + for var in self.stack.iter().rev() { if var.name == name && var.active { - return Some((slot, var.typ.clone(), var.scope, false)); + return Some(var.clone()); } } None } - fn find_upvalue(&self, name: &str) -> Option<(usize, Type, usize, bool)> { - for (slot, upvalue) in self.upvalues.iter().enumerate() { - //TODO ?? + fn find_upvalue(&self, name: &str) -> Option { + println!("UPVALUE!"); + for var in self.upvalues.iter().rev() { + if var.name == name && var.active { + return Some(var.clone()); + } } + None + } + + fn add_upvalue(&mut self, variable: Variable) -> Variable { + println!("{} - UPDOG", variable.name); + let new_variable = Variable { + outer_slot: variable.slot, + slot: self.upvalues.len(), + active: true, + upvalue: true, + ..variable + }; + self.upvalues.push(new_variable.clone()); + new_variable } } @@ -149,6 +173,7 @@ macro_rules! push_frame { { $compiler.frames.push(Frame { stack: Vec::new(), + upvalues: Vec::new(), scope: 0, variables_below: $compiler.frame().variables_below + $compiler.stack().len(), }); @@ -173,8 +198,12 @@ macro_rules! push_scope { $code; $compiler.frame_mut().scope -= 1; - for _ in ss..$compiler.stack().len() { - $block.add(Op::Pop, $compiler.line()); + for var in $compiler.frame().stack[ss..$compiler.stack().len()].iter().rev() { + if var.captured { + $block.add(Op::PopUpvalue, $compiler.line()); + } else { + $block.add(Op::Pop, $compiler.line()); + } } $compiler.stack_mut().truncate(ss); }; @@ -189,6 +218,7 @@ impl Compiler { frames: vec![Frame { stack: Vec::new(), + upvalues: Vec::new(), scope: 0, variables_below: 0, }], @@ -407,23 +437,36 @@ impl Compiler { } } - fn find_upvalue(&self, name: &str, start_at: usize) -> Option<(usize, Type, usize, bool)> { - - } - - fn find_variable(&mut self, name: &str, mut iterator: I) -> Option<(usize, Type, usize, bool)> - where I: Iterator { - if let Some(frame) = i.next() { + fn find_and_capture_variable<'a, I>(name: &str, mut iterator: I) -> Option + where I: Iterator { + if let Some(frame) = iterator.next() { if let Some(res) = frame.find_local(name) { + frame.stack[res.slot].captured = true; return Some(res); } if let Some(res) = frame.find_upvalue(name) { return Some(res); } + + if let Some(res) = Self::find_and_capture_variable(name, iterator) { + return Some(frame.add_upvalue(res)); + } } None } + fn find_variable(&mut self, name: &str) -> Option { + if let Some(res) = self.frame().find_local(name) { + return Some(res); + } + + if let Some(res) = self.frame().find_upvalue(name) { + return Some(res); + } + + return Self::find_and_capture_variable(name, self.frames.iter_mut().rev()); + } + fn call(&mut self, block: &mut Block) { expect!(self, Token::LeftParen, "Expected '(' at start of function call."); @@ -467,6 +510,7 @@ 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 _ret = push_frame!(self, function_block, { loop { match self.peek() { @@ -505,6 +549,8 @@ impl Compiler { } self.scope(&mut function_block); + // TODO(ed): Send the original place to find the upvalues, + // so we know from where to copy them. }); if !matches!(function_block.last_op(), Some(&Op::Return)) { @@ -515,7 +561,9 @@ impl Compiler { function_block.ty = Type::Function(args, Box::new(return_type)); let function_block = Rc::new(function_block); - block.add(Op::Constant(Value::Function(Rc::clone(&function_block))), self.line()); + + let func = Op::Constant(Value::Function(Vec::new(), Rc::clone(&function_block))); + block.add(func, self.line()); self.blocks.push(function_block); } @@ -524,16 +572,20 @@ impl Compiler { Token::Identifier(name) => name, __ => unreachable!(), }; - if let Some((slot, _, _)) = self.find_local(&name, block) { - block.add(Op::ReadLocal(slot), self.line()); + if let Some(var) = self.find_variable(&name) { + if var.upvalue { + block.add(Op::ReadUpvalue(var.slot), self.line()); + } else { + block.add(Op::ReadLocal(var.slot), self.line()); + } } else { error!(self, format!("Using undefined variable {}.", name)); } } fn define_variable(&mut self, name: &str, typ: Type, block: &mut Block) -> Result { - if let Some((_, _, level)) = self.find_local(&name, block) { - if level == self.frame().scope { + if let Some(var) = self.find_variable(&name) { + if var.scope == self.frame().scope { error!(self, format!("Multiple definitions of {} in this block.", name)); return Err(()); } @@ -543,6 +595,9 @@ impl Compiler { let scope = self.frame().scope; self.stack_mut().push(Variable { name: String::from(name), + captured: false, + outer_slot: 0, + slot, typ, scope, active: false, @@ -562,9 +617,13 @@ impl Compiler { } fn assign(&mut self, name: &str, block: &mut Block) { - if let Some((slot, _, _)) = self.find_local(&name, block) { + if let Some(var) = self.find_variable(&name) { self.expression(block); - block.add(Op::Assign(slot), self.line()); + if var.upvalue { + block.add(Op::AssignUpvalue(var.slot), self.line()); + } else { + block.add(Op::AssignLocal(var.slot), self.line()); + } } else { error!(self, format!("Using undefined variable {}.", name)); } @@ -774,8 +833,11 @@ impl Compiler { self.stack_mut().push(Variable { name: String::from("/main/"), typ: Type::Void, + outer_slot: 0, + slot: 0, scope: 0, active: false, + captured: false, upvalue: false, }); -- cgit v1.2.1 From d13695d2452e0468168240800a4cde88f220b646 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Wed, 20 Jan 2021 21:26:14 +0100 Subject: Typecheck upvalues --- src/compiler.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'src/compiler.rs') diff --git a/src/compiler.rs b/src/compiler.rs index c4afbf3..b7dad75 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -107,7 +107,10 @@ struct Variable { typ: Type, scope: usize, slot: usize, + outer_slot: usize, + outer_upvalue: bool, + active: bool, upvalue: bool, captured: bool, @@ -144,6 +147,7 @@ impl Frame { fn add_upvalue(&mut self, variable: Variable) -> Variable { println!("{} - UPDOG", variable.name); let new_variable = Variable { + outer_upvalue: variable.upvalue, outer_slot: variable.slot, slot: self.upvalues.len(), active: true, @@ -549,6 +553,11 @@ impl Compiler { } self.scope(&mut function_block); + + for var in self.frame().upvalues.iter() { + function_block.ups.push((var.outer_slot, var.outer_upvalue, var.typ.clone())); + } + println!("{:?}", function_block.ups); // TODO(ed): Send the original place to find the upvalues, // so we know from where to copy them. }); @@ -596,6 +605,7 @@ impl Compiler { self.stack_mut().push(Variable { name: String::from(name), captured: false, + outer_upvalue: false, outer_slot: 0, slot, typ, @@ -833,6 +843,7 @@ impl Compiler { self.stack_mut().push(Variable { name: String::from("/main/"), typ: Type::Void, + outer_upvalue: false, outer_slot: 0, slot: 0, scope: 0, -- cgit v1.2.1 From 5d43ce4ab4b9c8d3ca8a0cb21f99b25e87e58fb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Wed, 20 Jan 2021 22:30:57 +0100 Subject: Calling of functions, in functions --- src/compiler.rs | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) (limited to 'src/compiler.rs') diff --git a/src/compiler.rs b/src/compiler.rs index b7dad75..ad97783 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -125,7 +125,6 @@ struct Frame { impl Frame { fn find_local(&self, name: &str) -> Option { - println!("LOCAL!"); for var in self.stack.iter().rev() { if var.name == name && var.active { return Some(var.clone()); @@ -135,7 +134,6 @@ impl Frame { } fn find_upvalue(&self, name: &str) -> Option { - println!("UPVALUE!"); for var in self.upvalues.iter().rev() { if var.name == name && var.active { return Some(var.clone()); @@ -202,6 +200,7 @@ macro_rules! push_scope { $code; $compiler.frame_mut().scope -= 1; + for var in $compiler.frame().stack[ss..$compiler.stack().len()].iter().rev() { if var.captured { $block.add(Op::PopUpvalue, $compiler.line()); @@ -496,17 +495,15 @@ impl Compiler { } block.add(Op::Call(arity), self.line()); - - for _ in 0..arity { - block.add(Op::Pop, self.line()); - } } fn function(&mut self, block: &mut Block) { expect!(self, Token::Fn, "Expected 'fn' at start of function."); - let name = if !self.stack()[self.stack().len() - 1].active { - &self.stack()[self.stack().len() - 1].name + let top = self.stack().len() - 1; + let name = if !self.stack()[top].active { + self.stack_mut()[top].active = true; + &self.stack()[top].name } else { "anonumus function" }; @@ -562,9 +559,18 @@ impl Compiler { // so we know from where to copy them. }); - if !matches!(function_block.last_op(), Some(&Op::Return)) { - function_block.add(Op::Constant(Value::Nil), self.line()); - function_block.add(Op::Return, self.line()); + let mut prev = function_block.ops.len() - 1; + loop { + match function_block.ops[prev] { + Op::Pop | Op::PopUpvalue => {} + Op::Return => { break; } , + _ => { + function_block.add(Op::Constant(Value::Nil), self.line()); + function_block.add(Op::Return, self.line()); + break; + } + } + prev -= 1; } function_block.ty = Type::Function(args, Box::new(return_type)); -- cgit v1.2.1 From 914bc87fd0525ce042d279bff6a4c97477bfeb61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Wed, 20 Jan 2021 22:56:30 +0100 Subject: allow empty functions --- src/compiler.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'src/compiler.rs') diff --git a/src/compiler.rs b/src/compiler.rs index ad97783..727f177 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -559,9 +559,8 @@ impl Compiler { // so we know from where to copy them. }); - let mut prev = function_block.ops.len() - 1; - loop { - match function_block.ops[prev] { + for op in function_block.ops.iter().rev() { + match op { Op::Pop | Op::PopUpvalue => {} Op::Return => { break; } , _ => { @@ -570,7 +569,11 @@ impl Compiler { break; } } - prev -= 1; + } + + if function_block.ops.is_empty() { + function_block.add(Op::Constant(Value::Nil), self.line()); + function_block.add(Op::Return, self.line()); } function_block.ty = Type::Function(args, Box::new(return_type)); -- cgit v1.2.1 From 34fc35ce55fa31b30cbb3491b0bce9c2289abbdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Wed, 20 Jan 2021 22:56:50 +0100 Subject: trailing comma on nextable enum --- src/compiler.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/compiler.rs') diff --git a/src/compiler.rs b/src/compiler.rs index 727f177..e45e611 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -6,7 +6,7 @@ use crate::tokenizer::{Token, TokenStream}; use crate::vm::{Value, Block, Op}; macro_rules! nextable_enum { - ( $name:ident { $( $thing:ident ),* } ) => { + ( $name:ident { $( $thing:ident ),* $( , )? } ) => { #[derive(PartialEq, PartialOrd, Clone, Copy, Debug)] enum $name { $( $thing, )* @@ -43,7 +43,7 @@ nextable_enum!(Prec { Bool, Comp, Term, - Factor + Factor, }); #[derive(Debug, Clone)] -- cgit v1.2.1 From 1626c2bb70e369c25bbd0fe713bf03e3ff52dff6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Wed, 20 Jan 2021 23:11:49 +0100 Subject: parse function precedence --- src/compiler.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/compiler.rs') diff --git a/src/compiler.rs b/src/compiler.rs index e45e611..aca1b26 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -363,8 +363,6 @@ impl Compiler { | Token::NotEqual => self.binary(block), - Token::LeftParen => self.call(block), - _ => { return false; }, } return true; @@ -596,6 +594,9 @@ impl Compiler { } else { block.add(Op::ReadLocal(var.slot), self.line()); } + if self.peek() == Token::LeftParen { + self.call(block); + } } else { error!(self, format!("Using undefined variable {}.", name)); } -- cgit v1.2.1 From 9626aa05496a0e745252ba30bf64e8d020c6ec2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Wed, 20 Jan 2021 23:45:47 +0100 Subject: cleanup --- src/compiler.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'src/compiler.rs') diff --git a/src/compiler.rs b/src/compiler.rs index aca1b26..d72b8d3 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -143,7 +143,6 @@ impl Frame { } fn add_upvalue(&mut self, variable: Variable) -> Variable { - println!("{} - UPDOG", variable.name); let new_variable = Variable { outer_upvalue: variable.upvalue, outer_slot: variable.slot, @@ -552,9 +551,6 @@ impl Compiler { for var in self.frame().upvalues.iter() { function_block.ups.push((var.outer_slot, var.outer_upvalue, var.typ.clone())); } - println!("{:?}", function_block.ups); - // TODO(ed): Send the original place to find the upvalues, - // so we know from where to copy them. }); for op in function_block.ops.iter().rev() { @@ -586,7 +582,7 @@ impl Compiler { fn variable_expression(&mut self, block: &mut Block) { let name = match self.eat() { Token::Identifier(name) => name, - __ => unreachable!(), + _ => unreachable!(), }; if let Some(var) = self.find_variable(&name) { if var.upvalue { @@ -602,7 +598,7 @@ impl Compiler { } } - fn define_variable(&mut self, name: &str, typ: Type, block: &mut Block) -> Result { + fn define_variable(&mut self, name: &str, typ: Type, _block: &mut Block) -> Result { if let Some(var) = self.find_variable(&name) { if var.scope == self.frame().scope { error!(self, format!("Multiple definitions of {} in this block.", name)); -- cgit v1.2.1 From d261da01634c5fd62cd68f8c9c39a89422bdd398 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Thu, 21 Jan 2021 19:55:22 +0100 Subject: Rc> and closing upvalues --- src/compiler.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'src/compiler.rs') diff --git a/src/compiler.rs b/src/compiler.rs index d72b8d3..409d6a6 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -1,5 +1,6 @@ use std::path::{Path, PathBuf}; use std::rc::Rc; +use std::cell::RefCell; use crate::error::{Error, ErrorKind}; use crate::tokenizer::{Token, TokenStream}; @@ -79,7 +80,7 @@ impl From<&Value> for Type { Value::Float(_) => Type::Float, Value::Bool(_) => Type::Bool, Value::String(_) => Type::String, - Value::Function(_, block) => block.ty.clone(), + Value::Function(_, block) => block.borrow().ty.clone(), _ => Type::Void, } } @@ -96,7 +97,7 @@ impl Type { Type::String => Value::String(Rc::new("".to_string())), Type::Function(_, _) => Value::Function( Vec::new(), - Rc::new(Block::from_type(self))), + Rc::new(RefCell::new(Block::from_type(self)))), } } } @@ -166,7 +167,7 @@ struct Compiler { panic: bool, errors: Vec, - blocks: Vec>, + blocks: Vec>>, } macro_rules! push_frame { @@ -571,7 +572,7 @@ impl Compiler { } function_block.ty = Type::Function(args, Box::new(return_type)); - let function_block = Rc::new(function_block); + let function_block = Rc::new(RefCell::new(function_block)); let func = Op::Constant(Value::Function(Vec::new(), Rc::clone(&function_block))); @@ -845,7 +846,7 @@ impl Compiler { } - pub fn compile(&mut self, name: &str, file: &Path) -> Result>, Vec> { + pub fn compile(&mut self, name: &str, file: &Path) -> Result>>, Vec> { self.stack_mut().push(Variable { name: String::from("/main/"), typ: Type::Void, @@ -867,7 +868,7 @@ impl Compiler { block.add(Op::Return, self.line()); block.ty = Type::Function(Vec::new(), Box::new(Type::Void)); - self.blocks.insert(0, Rc::new(block)); + self.blocks.insert(0, Rc::new(RefCell::new(block))); if self.errors.is_empty() { Ok(self.blocks.clone()) @@ -877,6 +878,6 @@ impl Compiler { } } -pub fn compile(name: &str, file: &Path, tokens: TokenStream) -> Result>, Vec> { +pub fn compile(name: &str, file: &Path, tokens: TokenStream) -> Result>>, Vec> { Compiler::new(file, tokens).compile(name, file) } -- cgit v1.2.1 From 4448657f8443842e3ef75353c5fa87dfebb3cffd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Thu, 21 Jan 2021 20:56:38 +0100 Subject: Add type inference for upvalues --- src/compiler.rs | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/compiler.rs') diff --git a/src/compiler.rs b/src/compiler.rs index 409d6a6..70c9a51 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -87,6 +87,13 @@ impl From<&Value> for Type { } impl Type { + pub fn is_unkown(&self) -> bool { + match self { + Type::UnknownType => true, + _ => false, + } + } + pub fn as_value(&self) -> Value { match self { Type::Void => Value::Nil, -- cgit v1.2.1