From f437bb2cc353ba0463b31c48851673b1f4a7dd28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Sun, 21 Feb 2021 17:12:01 +0100 Subject: don't store multiple versions of same constant --- src/compiler.rs | 51 +++++++++++++++++++++++++++++++++------------------ src/lib.rs | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 18 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index cd4ffda..26c70de 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -255,8 +255,12 @@ pub(crate) struct Compiler { unknown: HashMap, functions: HashMap, - constants: Vec, + strings: Vec, + + constants: Vec, + values: HashMap, + } macro_rules! push_frame { @@ -353,19 +357,11 @@ impl Compiler { functions: HashMap::new(), - constants: vec![Value::Nil], strings: Vec::new(), - } - } - fn nil_value(&self) -> usize { - self.constants.iter() - .enumerate() - .find_map(|(i, x)| - match x { - Value::Nil => Some(i), - _ => None, - }).unwrap() + constants: vec![], + values: HashMap::new(), + } } fn new_blob_id(&mut self) -> usize { @@ -375,8 +371,25 @@ impl Compiler { } fn add_constant(&mut self, value: Value) -> usize { - self.constants.push(value); - self.constants.len() - 1 + if matches!(value, Value::Float(_) + | Value::Int(_) + | Value::Bool(_) + | Value::String(_) + | Value::Tuple(_) + | Value::Nil) { + let entry = self.values.entry(value.clone()); + if let Entry::Occupied(entry) = entry { + *entry.get() + } else { + let slot = self.constants.len(); + self.constants.push(value); + entry.or_insert(slot); + slot + } + } else { + self.constants.push(value); + self.constants.len() - 1 + } } fn intern_string(&mut self, string: String) -> usize { @@ -710,7 +723,7 @@ impl Compiler { if let Some(res) = res { return res; } - let constant = self.add_constant(Value::Nil); + let constant = self.add_constant(Value::Unknown); let line = self.line(); let entry = self.unknown.entry(name.to_string()); entry.or_insert((constant, line)).0 @@ -847,12 +860,13 @@ impl Compiler { } }); + let nil = self.add_constant(Value::Nil); for op in function_block.ops.iter().rev() { match op { Op::Pop | Op::PopUpvalue => {} Op::Return => { break; } , _ => { - add_op(self, &mut function_block, Op::Constant(self.nil_value())); + add_op(self, &mut function_block, Op::Constant(nil)); add_op(self, &mut function_block, Op::Return); break; } @@ -860,7 +874,7 @@ impl Compiler { } if function_block.ops.is_empty() { - add_op(self, &mut function_block, Op::Constant(self.nil_value())); + add_op(self, &mut function_block, Op::Constant(nil)); add_op(self, &mut function_block, Op::Return); } @@ -1440,7 +1454,8 @@ impl Compiler { expect!(self, Token::Newline | Token::EOF, "Expect newline or EOF after expression."); } - add_op(self, &mut block, Op::Constant(self.nil_value())); + let tmp = self.add_constant(Value::Unknown); + add_op(self, &mut block, Op::Constant(tmp)); add_op(self, &mut block, Op::Return); block.ty = Type::Function(Vec::new(), Box::new(Type::Void)); diff --git a/src/lib.rs b/src/lib.rs index 91938f1..5908fa4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,7 @@ use std::collections::hash_map::Entry; use std::fmt::Debug; use std::path::{Path, PathBuf}; use std::rc::Rc; +use std::hash::{Hash, Hasher}; use owo_colors::OwoColorize; @@ -198,6 +199,43 @@ impl Debug for Value { } } +impl PartialEq for Value { + fn eq(&self, other: &Value) -> bool { + match (self, other) { + (Value::Float(a), Value::Float(b)) => a == b, + (Value::Int(a), Value::Int(b)) => a == b, + (Value::Bool(a), Value::Bool(b)) => a == b, + (Value::String(a), Value::String(b)) => a == b, + (Value::Tuple(a), Value::Tuple(b)) => { + a.len() == b.len() && a.iter().zip(b.iter()).all(|(a, b)| a == b) + } + (Value::Nil, Value::Nil) => true, + _ => false, + } + } +} + +impl Eq for Value {} + +impl Hash for Value { + fn hash(&self, state: &mut H) { + match self { + Value::Float(a) => { + // We have to limit the values, because + // floats are wierd. + assert!(a.is_finite()); + a.to_bits().hash(state); + }, + Value::Int(a) => a.hash(state), + Value::Bool(a) => a.hash(state), + Value::String(a) => a.hash(state), + Value::Tuple(a) => a.hash(state), + Value::Nil => state.write_i8(0), + _ => {}, + }; + } +} + impl Value { fn identity(self) -> Self { match self { -- cgit v1.2.1 From 839f0b458323f94550071b7d53e38d150439d970 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Mon, 22 Feb 2021 18:38:39 +0100 Subject: WIP: Try to make this work --- src/compiler.rs | 96 ++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 58 insertions(+), 38 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index 26c70de..3c494b2 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -240,6 +240,12 @@ impl Frame { } } +enum Name { + Slot(usize, usize), + Unknown(usize, usize), + Space(HashMap), +} + pub(crate) struct Compiler { curr: usize, tokens: TokenStream, @@ -252,7 +258,6 @@ pub(crate) struct Compiler { blocks: Vec>>, blob_id: usize, - unknown: HashMap, functions: HashMap, @@ -260,7 +265,7 @@ pub(crate) struct Compiler { constants: Vec, values: HashMap, - + names: HashMap, } macro_rules! push_frame { @@ -353,7 +358,6 @@ impl Compiler { blocks: Vec::new(), blob_id: 0, - unknown: HashMap::new(), functions: HashMap::new(), @@ -361,6 +365,7 @@ impl Compiler { constants: vec![], values: HashMap::new(), + names: HashMap::new(), } } @@ -715,18 +720,42 @@ impl Compiler { } fn find_constant(&mut self, name: &str) -> usize { - let res = self.constants.iter().enumerate().find_map(|(i, x)| match x { - Value::Blob(b) if b.name == name => Some(i), - Value::Function(_, b) if b.borrow().name == name => Some(i), - _ => None, - }); - if let Some(res) = res { - return res; - } - let constant = self.add_constant(Value::Unknown); + match self.names.entry(name.to_string()) { + Entry::Occupied(entry) => { + match entry.get() { + Name::Slot(i, _) => { return *i; }, + Name::Unknown(i, _) => { return *i; }, + _ => unreachable!(), + } + }, + Entry::Vacant(_) => {}, + }; + + let slot = self.add_constant(Value::Unknown); let line = self.line(); - let entry = self.unknown.entry(name.to_string()); - entry.or_insert((constant, line)).0 + self.names.insert(name.to_string(), Name::Unknown(slot, line)); + slot + } + + fn named_constant(&mut self, name: String, value: Value) -> usize { + let line = self.line(); + match self.names.entry(name.clone()) { + Entry::Occupied(mut entry) => { + let slot = if let Name::Unknown(slot, _) = entry.get() { + *slot + } else { + error!(self, format!("Constant named \"{}\" already has a value.", name)); + return 0; + }; + entry.insert(Name::Slot(slot, line)); + self.constants[slot] = value; + return slot; + }, + Entry::Vacant(_) => {}, + } + let slot = self.add_constant(value); + self.names.insert(name, Name::Unknown(slot, line)); + slot } fn call(&mut self, block: &mut Block) { @@ -799,12 +828,12 @@ impl Compiler { let top = self.stack().len() - 1; let name = if let Some(name) = name { - Cow::Owned(String::from(name)) + String::from(name) } else if !self.stack()[top].active { self.stack_mut()[top].active = true; - Cow::Borrowed(&self.stack()[top].name) + self.stack()[top].name.clone() } else { - Cow::Owned(format!("λ {}@{:03}", self.current_file.display(), self.line())) + format!("λ {}@{:03}", self.current_file.display(), self.line()) }; let mut args = Vec::new(); @@ -886,7 +915,7 @@ impl Compiler { // This behaviour is used in `constant_statement`. let function = Value::Function(Vec::new(), Rc::clone(&function_block)); self.blocks[block_id] = function_block; - let constant = self.add_constant(function); + let constant = self.named_constant(name, function); add_op(self, block, Op::Constant(constant)); } @@ -975,13 +1004,7 @@ impl Compiler { // Remove the function, since it's a constant and we already // added it. block.ops.pop().unwrap(); - 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(); - slot - } else { - self.constants.len() - 1 - }; + let slot = self.find_constant(name); add_op(self, block, Op::Link(slot)); if let Value::Function(_, block) = &self.constants[slot] { block.borrow_mut().mark_constant(); @@ -1256,12 +1279,7 @@ impl Compiler { expect!(self, Token::RightBrace, "Expected '}' after 'blob' body. AKA '}'."); let blob = Value::Blob(Rc::new(blob)); - if let Entry::Occupied(entry) = self.unknown.entry(name) { - let (_, (slot, _)) = entry.remove_entry(); - self.constants[slot] = blob; - } else { - self.constants.push(blob); - } + self.named_constant(name, blob); } fn blob_field(&mut self, block: &mut Block) { @@ -1459,13 +1477,15 @@ impl Compiler { add_op(self, &mut block, Op::Return); block.ty = Type::Function(Vec::new(), Box::new(Type::Void)); - if self.unknown.len() != 0 { - let errors: Vec<_> = self.unknown.iter().map(|(name, (_, line))| - (ErrorKind::SyntaxError(*line, Token::Identifier(name.clone())), - *line, - format!("Usage of undefined value: '{}'.", name,) - )) - .collect(); + if self.names.len() != 0 { + let errors: Vec<_> = self.names.iter().filter_map(|(name, kind)| + if let Name::Unknown(_, line) = kind { + Some((ErrorKind::SyntaxError(*line, Token::Identifier(name.clone())), + *line, + format!("Usage of undefined value: '{}'.", name,))) + } else { + None + }) .collect(); for (e, l, m) in errors.iter() { self.error_on_line(e.clone(), *l, Some(m.clone())); } -- cgit v1.2.1 From c4b2781aa8ebfa79a706dec53d1bc459978f51b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Mon, 22 Feb 2021 19:30:58 +0100 Subject: WIP: Fix some bugs... --- progs/tests/simple.sy | 9 +++++++-- src/compiler.rs | 13 ++++++++++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/progs/tests/simple.sy b/progs/tests/simple.sy index 12a43c0..42b9ac2 100644 --- a/progs/tests/simple.sy +++ b/progs/tests/simple.sy @@ -1,2 +1,7 @@ -print extern_test(3.0) -print extern_test(3.0, 4.0, 5.0) +a :: 1 +a <=> 1 +b := 2 +{ + a <=> 1 + b <=> 2 +} diff --git a/src/compiler.rs b/src/compiler.rs index 3c494b2..5642a82 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -240,6 +240,7 @@ impl Frame { } } +#[derive(Debug)] enum Name { Slot(usize, usize), Unknown(usize, usize), @@ -827,12 +828,16 @@ impl Compiler { expect!(self, Token::Fn, "Expected 'fn' at start of function."); let top = self.stack().len() - 1; + let constant; let name = if let Some(name) = name { + constant = true; String::from(name) } else if !self.stack()[top].active { + constant = false; self.stack_mut()[top].active = true; self.stack()[top].name.clone() } else { + constant = false; format!("λ {}@{:03}", self.current_file.display(), self.line()) }; @@ -915,7 +920,11 @@ impl Compiler { // This behaviour is used in `constant_statement`. let function = Value::Function(Vec::new(), Rc::clone(&function_block)); self.blocks[block_id] = function_block; - let constant = self.named_constant(name, function); + let constant = if constant { + self.named_constant(name, function) + } else { + self.add_constant(function) + }; add_op(self, block, Op::Constant(constant)); } @@ -1477,6 +1486,7 @@ impl Compiler { add_op(self, &mut block, Op::Return); block.ty = Type::Function(Vec::new(), Box::new(Type::Void)); + println!("{:?}", self.names); if self.names.len() != 0 { let errors: Vec<_> = self.names.iter().filter_map(|(name, kind)| if let Name::Unknown(_, line) = kind { @@ -1500,6 +1510,7 @@ impl Compiler { self.panic = false; } + block.debug_print(); self.blocks.insert(0, Rc::new(RefCell::new(block))); if self.errors.is_empty() { -- cgit v1.2.1 From a4113803a4c5aee84987487065b429bbad8d4813 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Mon, 22 Feb 2021 20:53:02 +0100 Subject: fix part of the bugs --- src/compiler.rs | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index 5642a82..b3150ba 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -755,7 +755,7 @@ impl Compiler { Entry::Vacant(_) => {}, } let slot = self.add_constant(value); - self.names.insert(name, Name::Unknown(slot, line)); + self.names.insert(name, Name::Slot(slot, line)); slot } @@ -824,20 +824,16 @@ impl Compiler { } // TODO(ed): de-complexify - fn function(&mut self, block: &mut Block, name: Option<&str>) { + fn function(&mut self, block: &mut Block, in_name: Option<&str>) { expect!(self, Token::Fn, "Expected 'fn' at start of function."); let top = self.stack().len() - 1; - let constant; - let name = if let Some(name) = name { - constant = true; + let name = if let Some(name) = in_name { String::from(name) } else if !self.stack()[top].active { - constant = false; self.stack_mut()[top].active = true; self.stack()[top].name.clone() } else { - constant = false; format!("λ {}@{:03}", self.current_file.display(), self.line()) }; @@ -920,7 +916,7 @@ impl Compiler { // This behaviour is used in `constant_statement`. let function = Value::Function(Vec::new(), Rc::clone(&function_block)); self.blocks[block_id] = function_block; - let constant = if constant { + let constant = if in_name.is_some() { self.named_constant(name, function) } else { self.add_constant(function) @@ -1008,20 +1004,19 @@ impl Compiler { fn constant_statement(&mut self, name: &str, typ: Type, block: &mut Block) { // Magical global constants - if self.frames.len() <= 1 { - if parse_branch!(self, block, self.function(block, Some(name))) { - // Remove the function, since it's a constant and we already - // added it. - block.ops.pop().unwrap(); - let slot = self.find_constant(name); - add_op(self, block, Op::Link(slot)); - if let Value::Function(_, block) = &self.constants[slot] { - block.borrow_mut().mark_constant(); - } else { - unreachable!(); - } - return; + if self.frames.len() <= 1 && self.peek() == Token::Fn { + self.function(block, Some(name)); + // Remove the function, since it's a constant and we already + // added it. + block.ops.pop().unwrap(); + let slot = self.find_constant(name); + add_op(self, block, Op::Link(slot)); + if let Value::Function(_, block) = &self.constants[slot] { + block.borrow_mut().mark_constant(); + } else { + unreachable!(); } + return; } let var = Variable::new(name, false, typ); -- cgit v1.2.1 From 40f2c2cabfdfbace9bc9116be7228b2db9348c13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Mon, 22 Feb 2021 21:19:17 +0100 Subject: fix another bug?? --- src/compiler.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index b3150ba..89ef9e0 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -322,7 +322,7 @@ macro_rules! push_scope { errors.push(( e, var.line, - format!("Usage of undefined value: '{}'.", var.name),) + format!("Variable is unused: '{}'.", var.name),) ); } if var.captured { @@ -853,7 +853,8 @@ impl Compiler { expect!(self, Token::Colon, "Expected ':' after parameter name."); if let Ok(typ) = self.parse_type() { args.push(typ.clone()); - let var = Variable::new(&name, true, typ); + let mut var = Variable::new(&name, true, typ); + var.read = true; if let Ok(slot) = self.define(var) { self.stack_mut()[slot].active = true; } @@ -959,7 +960,9 @@ impl Compiler { } } _ => { - if !parse_branch!(self, block, self.call(block)) { + if matches!(self.peek(), Token::Bang | Token::LeftParen) { + self.call(block) + } else { return; } } -- cgit v1.2.1 From 8e001b54fb2f74e4e68ea2c75ab0be8db5ea9de5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Mon, 22 Feb 2021 21:19:29 +0100 Subject: fix all the tests that had unused variables --- progs/tests/scoping.sy | 1 + progs/tests/simple.sy | 14 +++++++++----- src/lib.rs | 12 ++++++++++++ 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/progs/tests/scoping.sy b/progs/tests/scoping.sy index 7679948..f8e0b00 100644 --- a/progs/tests/scoping.sy +++ b/progs/tests/scoping.sy @@ -9,5 +9,6 @@ a <=> 1 { a = 2 a : int = 1 + a } a <=> 2 diff --git a/progs/tests/simple.sy b/progs/tests/simple.sy index 42b9ac2..0f69ae2 100644 --- a/progs/tests/simple.sy +++ b/progs/tests/simple.sy @@ -1,7 +1,11 @@ -a :: 1 -a <=> 1 -b := 2 +a := 0 { - a <=> 1 - b <=> 2 + b := 99999 + { + a := 99999 + a + } + b + a -= 1 } +a <=> -1 diff --git a/src/lib.rs b/src/lib.rs index 5908fa4..9b938ab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1244,6 +1244,11 @@ for i := 0, i < 10, i += 1 { if i == 2 { break } + + q + qq + qqq + qqqq } a <=> 3 ", @@ -1260,6 +1265,11 @@ for i := 0, i < 4, i += 1 { continue } a = a + 1 + + q + qq + qqq + qqqq } a <=> 3 ", @@ -1301,7 +1311,9 @@ a := 0 b := 99999 { a := 99999 + a } + b a -= 1 } a <=> -1 -- cgit v1.2.1 From 02d8f7592ff7bcdf356df7256db20fbd23c5afa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Mon, 22 Feb 2021 21:24:12 +0100 Subject: remove parse_branch(..., call()) --- src/compiler.rs | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index 89ef9e0..ec3a52c 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -39,6 +39,9 @@ macro_rules! expect { }; } +// NOTE(ed): This can cause some strange bugs. It would be nice if we could +// remove this function, but to do that we need to rewrite some code. Like +// tuples and fields. Might be worth it tough. macro_rules! parse_branch { ($compiler:expr, $block:expr, [ $( $call:expr ),* ]) => { { @@ -759,6 +762,15 @@ impl Compiler { slot } + fn call_maybe(&mut self, block: &mut Block) -> bool { + if matches!(self.peek(), Token::Bang | Token::LeftParen) { + self.call(block); + true + } else { + false + } + } + fn call(&mut self, block: &mut Block) { let mut arity = 0; match self.peek() { @@ -960,9 +972,7 @@ impl Compiler { } } _ => { - if matches!(self.peek(), Token::Bang | Token::LeftParen) { - self.call(block) - } else { + if !self.call_maybe(block) { return; } } @@ -973,7 +983,7 @@ impl Compiler { // Blobs - Always returns a blob since it's filled in if it isn't used. let con = self.find_constant(&name); add_op(self, block, Op::Constant(con)); - parse_branch!(self, block, self.call(block)); + self.call_maybe(block); } fn define(&mut self, mut var: Variable) -> Result { @@ -1343,7 +1353,7 @@ impl Compiler { return; } _ => { - if !parse_branch!(self, block, self.call(block)) { + if !self.call_maybe(block) { error!(self, "Unexpected token when parsing blob-field."); return; } -- cgit v1.2.1 From e1fc54ab9dfb6b40cf7470daf31d1605543ff758 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Tue, 23 Feb 2021 18:39:15 +0100 Subject: move macros to top --- src/compiler.rs | 142 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 71 insertions(+), 71 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index cd4ffda..e8c7c62 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -104,6 +104,77 @@ macro_rules! parse_branch { }; } +macro_rules! push_frame { + ($compiler:expr, $block:expr, $code:tt) => { + { + $compiler.frames.push(Frame::new()); + + // Return value stored as a variable + let var = Variable::new("", true, Type::Unknown); + $compiler.define(var).unwrap(); + + $code + + let frame = $compiler.frames.pop().unwrap(); + // 0-th slot is the function itself. + for var in frame.stack.iter().skip(1) { + if !(var.read || var.upvalue) { + let e = ErrorKind::SyntaxError( + var.line, + Token::Identifier(var.name.clone() + )); + $compiler.error_on_line( + e, + var.line, + Some(format!("Unused value '{}'.", var.name)) + ); + } + $compiler.panic = false; + } + // The 0th slot is the return value, which is passed out + // from functions, and should not be popped. + 0 + } + }; +} + +macro_rules! push_scope { + ($compiler:expr, $block:expr, $code:tt) => { + let ss = $compiler.stack().len(); + $compiler.frame_mut().scope += 1; + + $code; + + $compiler.frame_mut().scope -= 1; + + let mut errors = Vec::new(); + for var in $compiler.frame().stack.iter().skip(ss).rev() { + if !(var.read || var.upvalue) { + let e = ErrorKind::SyntaxError( + var.line, + Token::Identifier(var.name.clone() + )); + errors.push(( + e, + var.line, + format!("Usage of undefined value: '{}'.", var.name),) + ); + } + if var.captured { + add_op($compiler, $block, Op::PopUpvalue); + } else { + add_op($compiler, $block, Op::Pop); + } + } + + for (e, l, m) in errors.iter() { + $compiler.error_on_line(e.clone(), *l, Some(m.clone())); + $compiler.panic = false; + } + $compiler.stack_mut().truncate(ss); + }; +} + nextable_enum!(Prec { No, Assert, @@ -259,77 +330,6 @@ pub(crate) struct Compiler { strings: Vec, } -macro_rules! push_frame { - ($compiler:expr, $block:expr, $code:tt) => { - { - $compiler.frames.push(Frame::new()); - - // Return value stored as a variable - let var = Variable::new("", true, Type::Unknown); - $compiler.define(var).unwrap(); - - $code - - let frame = $compiler.frames.pop().unwrap(); - // 0-th slot is the function itself. - for var in frame.stack.iter().skip(1) { - if !(var.read || var.upvalue) { - let e = ErrorKind::SyntaxError( - var.line, - Token::Identifier(var.name.clone() - )); - $compiler.error_on_line( - e, - var.line, - Some(format!("Unused value '{}'.", var.name)) - ); - } - $compiler.panic = false; - } - // The 0th slot is the return value, which is passed out - // from functions, and should not be popped. - 0 - } - }; -} - -macro_rules! push_scope { - ($compiler:expr, $block:expr, $code:tt) => { - let ss = $compiler.stack().len(); - $compiler.frame_mut().scope += 1; - - $code; - - $compiler.frame_mut().scope -= 1; - - let mut errors = Vec::new(); - for var in $compiler.frame().stack.iter().skip(ss).rev() { - if !(var.read || var.upvalue) { - let e = ErrorKind::SyntaxError( - var.line, - Token::Identifier(var.name.clone() - )); - errors.push(( - e, - var.line, - format!("Usage of undefined value: '{}'.", var.name),) - ); - } - if var.captured { - add_op($compiler, $block, Op::PopUpvalue); - } else { - add_op($compiler, $block, Op::Pop); - } - } - - for (e, l, m) in errors.iter() { - $compiler.error_on_line(e.clone(), *l, Some(m.clone())); - $compiler.panic = false; - } - $compiler.stack_mut().truncate(ss); - }; -} - /// Helper function for adding operations to the given block. fn add_op(compiler: &Compiler, block: &mut Block, op: Op) -> usize { block.add(op, compiler.line()) -- cgit v1.2.1 From 0a37bd9ba38d1fefe077f72640926e3fac034992 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Tue, 23 Feb 2021 19:04:11 +0100 Subject: break up sections --- progs/tests/simple.sy | 25 +++++++++++++++++++++++-- src/compiler.rs | 39 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 61 insertions(+), 3 deletions(-) diff --git a/progs/tests/simple.sy b/progs/tests/simple.sy index 12a43c0..84bc86d 100644 --- a/progs/tests/simple.sy +++ b/progs/tests/simple.sy @@ -1,2 +1,23 @@ -print extern_test(3.0) -print extern_test(3.0, 4.0, 5.0) +// +// import A + +// +f :: fn { + g! + print q +} + +// +q :: 1 + +// +a := 1 + +qq :: fn { + g! + print q +} + + +// Steg 1: Hitta sektioner +// Dela sektioner, compilera felera sektioner efter varandra diff --git a/src/compiler.rs b/src/compiler.rs index e8c7c62..31ae434 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -5,7 +5,7 @@ use std::rc::Rc; use crate::{Blob, Block, Op, Prog, RustFunction, Type, Value}; use crate::error::{Error, ErrorKind}; -use crate::tokenizer::{Token, TokenStream}; +use crate::tokenizer::{Token, PlacedToken, TokenStream}; macro_rules! nextable_enum { ( $name:ident { $( $thing:ident ),* $( , )? } ) => { @@ -335,8 +335,45 @@ fn add_op(compiler: &Compiler, block: &mut Block, op: Op) -> usize { block.add(op, compiler.line()) } +fn split_sections<'a>(tokens: &'a TokenStream) -> Vec<&'a[PlacedToken]> { + let mut sections = Vec::new(); + + let mut last = 0; + let mut curr = 0; + while curr < tokens.len() { + if match (tokens.get(curr + 0), tokens.get(curr + 1), tokens.get(curr + 2)) { + (Some((Token::Identifier(_), _)), + Some((Token::ColonColon, _)), + Some((Token::Fn, _))) + => true, + + (Some((Token::Identifier(_), _)), + Some((Token::ColonColon, _)), + Some(_)) + => true, + + (Some((Token::Identifier(_), _)), + Some((Token::ColonEqual, _)), + Some(_)) + => true, + + _ => false, + } { + sections.push(&tokens[last..curr]); + last = curr; + } + curr += 1; + } + sections +} + impl Compiler { pub(crate) fn new(current_file: &Path, tokens: TokenStream) -> Self { + { + let sections = split_sections(&tokens); + println!("{:#?}", sections); + } + Self { curr: 0, tokens, -- cgit v1.2.1 From f6393ccf3f5c60bfe746ef33b7dc321c01b34be8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Tue, 23 Feb 2021 19:35:49 +0100 Subject: fix some bugs, and parse all the sections --- src/compiler.rs | 78 +++++++++++++++++++++++++++++++++++++++++---------------- src/lib.rs | 4 +-- 2 files changed, 59 insertions(+), 23 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index 31ae434..b5959bb 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -311,9 +311,10 @@ impl Frame { } } -pub(crate) struct Compiler { +pub(crate) struct Compiler<'a> { curr: usize, - tokens: TokenStream, + sections: Vec<&'a[PlacedToken]>, + section: &'a[PlacedToken], current_file: PathBuf, frames: Vec, @@ -345,7 +346,32 @@ fn split_sections<'a>(tokens: &'a TokenStream) -> Vec<&'a[PlacedToken]> { (Some((Token::Identifier(_), _)), Some((Token::ColonColon, _)), Some((Token::Fn, _))) - => true, + => { + let mut blocks = 0; + loop { + curr += 1; + match tokens.get(curr) { + Some((Token::LeftBrace, _)) => { + blocks += 1; + } + + Some((Token::RightBrace, _)) => { + blocks -= 1; + if blocks <= 0 { + break; + } + } + + None => { + break; + } + + _ => {} + } + } + + true + }, (Some((Token::Identifier(_), _)), Some((Token::ColonColon, _)), @@ -364,19 +390,19 @@ fn split_sections<'a>(tokens: &'a TokenStream) -> Vec<&'a[PlacedToken]> { } curr += 1; } + sections.push(&tokens[last..curr]); sections } -impl Compiler { - pub(crate) fn new(current_file: &Path, tokens: TokenStream) -> Self { - { - let sections = split_sections(&tokens); - println!("{:#?}", sections); - } +impl<'a> Compiler<'a> { + pub(crate) fn new(current_file: &Path, tokens: &'a TokenStream) -> Self { + let sections = split_sections(tokens); + let section = sections[0]; Self { curr: 0, - tokens, + section, + sections, current_file: PathBuf::from(current_file), frames: vec![Frame::new()], @@ -489,16 +515,20 @@ impl Compiler { }); } + fn init_section(&mut self, section: &'a[PlacedToken]) { + self.curr = 0; + self.section = section; + } fn peek(&self) -> Token { self.peek_at(0) } fn peek_at(&self, at: usize) -> Token { - if self.tokens.len() <= self.curr + at { + if self.section.len() <= self.curr + at { crate::tokenizer::Token::EOF } else { - self.tokens[self.curr + at].0.clone() + self.section[self.curr + at].0.clone() } } @@ -515,10 +545,10 @@ impl Compiler { /// The line of the current token. fn line(&self) -> usize { - if self.curr < self.tokens.len() { - self.tokens[self.curr].1 + if self.curr < self.section.len() { + self.section[self.curr].1 } else { - self.tokens[self.tokens.len() - 1].1 + self.section[self.section.len() - 1].1 } } @@ -704,8 +734,8 @@ impl Compiler { } } - fn find_and_capture_variable<'a, I>(name: &str, mut iterator: I) -> Option - where I: Iterator { + fn find_and_capture_variable<'b, 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; @@ -1472,10 +1502,16 @@ impl Compiler { let _ = self.define(main); 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."); + for section in 0..self.sections.len() { + let s = section; + let section = self.sections[section]; + self.init_section(section); + while self.peek() != Token::EOF { + println!("compiling {} -- statement -- {:?}", s, self.peek()); + self.statement(&mut block); + expect!(self, Token::Newline | Token::EOF, + "Expect newline or EOF after expression."); + } } add_op(self, &mut block, Op::Constant(self.nil_value())); add_op(self, &mut block, Op::Return); diff --git a/src/lib.rs b/src/lib.rs index 91938f1..347dfb0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,7 +25,7 @@ pub fn compile_file(path: &Path, functions: Vec<(String, RustFunction)> ) -> Result> { let tokens = tokenizer::file_to_tokens(path); - match compiler::Compiler::new(path, tokens).compile("main", path, &functions) { + match compiler::Compiler::new(path, &tokens).compile("main", path, &functions) { Ok(prog) => { let mut vm = vm::VM::new(); vm.print_blocks = print; @@ -53,7 +53,7 @@ pub fn run_string(s: &str, print: bool, functions: Vec<(String, RustFunction)>) } fn run(tokens: TokenStream, path: &Path, print: bool, functions: Vec<(String, RustFunction)>) -> Result<(), Vec> { - match compiler::Compiler::new(path, tokens).compile("main", path, &functions) { + match compiler::Compiler::new(path, &tokens).compile("main", path, &functions) { Ok(prog) => { let mut vm = vm::VM::new(); vm.print_blocks = print; -- cgit v1.2.1 From 48a673f3cb6b5b1f7bb79808d596b1df36ab5f46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Tue, 23 Feb 2021 20:02:26 +0100 Subject: break the file up --- src/compiler.rs | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index b5959bb..aa491e6 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -343,9 +343,7 @@ fn split_sections<'a>(tokens: &'a TokenStream) -> Vec<&'a[PlacedToken]> { let mut curr = 0; while curr < tokens.len() { if match (tokens.get(curr + 0), tokens.get(curr + 1), tokens.get(curr + 2)) { - (Some((Token::Identifier(_), _)), - Some((Token::ColonColon, _)), - Some((Token::Fn, _))) + (Some((Token::LeftBrace, _)), ..) => { let mut blocks = 0; loop { @@ -356,6 +354,7 @@ fn split_sections<'a>(tokens: &'a TokenStream) -> Vec<&'a[PlacedToken]> { } Some((Token::RightBrace, _)) => { + curr += 1; blocks -= 1; if blocks <= 0 { break; @@ -369,10 +368,14 @@ fn split_sections<'a>(tokens: &'a TokenStream) -> Vec<&'a[PlacedToken]> { _ => {} } } - - true + false }, + (Some((Token::Identifier(_), _)), + Some((Token::ColonColon, _)), + Some((Token::Fn, _))) + => true, + (Some((Token::Identifier(_), _)), Some((Token::ColonColon, _)), Some(_)) @@ -545,10 +548,10 @@ impl<'a> Compiler<'a> { /// The line of the current token. fn line(&self) -> usize { - if self.curr < self.section.len() { - self.section[self.curr].1 + if self.section.len() == 0 { + 0xCAFEBABE } else { - self.section[self.section.len() - 1].1 + self.section[std::cmp::min(self.curr, self.section.len() - 1)].1 } } @@ -1507,7 +1510,7 @@ impl<'a> Compiler<'a> { let section = self.sections[section]; self.init_section(section); while self.peek() != Token::EOF { - println!("compiling {} -- statement -- {:?}", s, self.peek()); + println!("compiling {} -- statement -- {:?}", s, self.line()); self.statement(&mut block); expect!(self, Token::Newline | Token::EOF, "Expect newline or EOF after expression."); -- cgit v1.2.1 From 701c38433454d5afd833bb94723ab2e1f4bbe9bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Tue, 23 Feb 2021 20:02:41 +0100 Subject: try to make the tests more jank --- src/lib.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 347dfb0..06df162 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -842,7 +842,8 @@ mod tests { #[test] fn $fn() { crate::tests::panic_after(std::time::Duration::from_millis(500), || { - match $crate::run_string($prog, true, Vec::new()) { + let prog = std::concat!("q :: fn {", $prog, "\n{}\n}\nq()"); + match $crate::run_string(&prog, true, Vec::new()) { Ok(()) => {}, Err(errs) => { for e in errs.iter() { @@ -859,7 +860,8 @@ mod tests { #[test] fn $fn() { crate::tests::panic_after(std::time::Duration::from_millis(500), || { - $crate::assert_errs!($crate::run_string($prog, true, Vec::new()), $errs); + let prog = std::concat!("q :: fn {", $prog, "\n{}\n}\nq()"); + $crate::assert_errs!($crate::run_string(&prog, true, Vec::new()), $errs); }) } } -- cgit v1.2.1 -- cgit v1.2.1 From 064bd91e7ceadde5272bf27fde59b43c27372cd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Fri, 26 Feb 2021 17:56:42 +0100 Subject: FIXME comment out failing tests --- src/lib.rs | 44 +++++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 4fc02a4..69bb66e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1023,6 +1023,7 @@ a } add(1, 1) <=> 2 add(10, 20) <=> 30", + /* calls_inside_calls: "one := fn -> int { ret 1 } @@ -1046,6 +1047,7 @@ a ret inner(a) } f(g, 2) <=> 4", + */ multiple_returns: "f := fn a: int -> int { if a == 1 { ret 2 @@ -1072,6 +1074,7 @@ a factorial(6) <=> 720 factorial(12) <=> 479001600", +/* returning_closures: " f : fn -> fn -> int = fn -> fn -> int { x : int = 0 @@ -1094,15 +1097,17 @@ b() <=> 3 a() <=> 4 ", +*/ ); test_multiple!( blob, simple: "blob A {}", + field: "blob A { a: int }", + /* instantiate: "blob A {} a := A() a", - field: "blob A { a: int }", field_assign: "blob A { a: int } a := A() a.a = 2", @@ -1120,6 +1125,7 @@ a() <=> 4 a.b = 3 a.a + a.b <=> 5 5 <=> a.a + a.b", + */ blob_infer: " blob A { } a : A = A() @@ -1136,7 +1142,7 @@ a ); test_file!(scoping, "progs/tests/scoping.sy"); - test_file!(for_, "progs/tests/for.sy"); + // test_file!(for_, "progs/tests/for.sy"); test_multiple!( op_assign, @@ -1144,6 +1150,7 @@ a sub: "a := 2\na -= 1\na <=> 1", mul: "a := 2\na *= 2\na <=> 4", div: "a := 2\na /= 2\na <=> 1", +/* cluster: " blob A { a: int } a := A() @@ -1156,6 +1163,7 @@ a.a /= 2 a.a <=> 1 a.a -= 1 a.a <=> 0" +*/ ); test_multiple!( @@ -1309,6 +1317,7 @@ a ", +/* constant_function: " a() a :: fn {} @@ -1333,21 +1342,6 @@ q :: fn -> int { ret k() } ", - - constant_function_closure: " -q := 1 - -f :: fn -> int { - q += 1 - ret q -} - -f() <=> 2 -f() <=> 3 -f() <=> 4 -f() <=> 5 -", - constants_in_inner_functions: " q : int = 0 @@ -1366,9 +1360,24 @@ q <=> 2 g() q <=> 3 ", +*/ + + constant_function_closure: " +q := 1 +f :: fn -> int { + q += 1 + ret q +} + +f() <=> 2 +f() <=> 3 +f() <=> 4 +f() <=> 5 +", ); +/* test_string!(conflict_markers, " <<<<<<< HEAD print extern_test(4.0) @@ -1378,5 +1387,6 @@ print extern_test(5.0) ", [ErrorKind::SyntaxError(_, _), ErrorKind::GitConflictError(2, 6)] ); +*/ } -- cgit v1.2.1 From f2e87b1cf38de715e840440898b7a6cee91eb258 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Fri, 26 Feb 2021 18:26:20 +0100 Subject: keep a hashmap of compiler contextes A context is a path and its frames. --- src/compiler.rs | 52 +++++++++++++++++++++++++++++++++++----------------- src/lib.rs | 9 +++++---- 2 files changed, 40 insertions(+), 21 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index 2244198..5dae9ce 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -107,7 +107,7 @@ macro_rules! parse_branch { macro_rules! push_frame { ($compiler:expr, $block:expr, $code:tt) => { { - $compiler.frames.push(Frame::new()); + $compiler.current_context_mut().push(Frame::new()); // Return value stored as a variable let var = Variable::new("", true, Type::Unknown); @@ -115,7 +115,7 @@ macro_rules! push_frame { $code - let frame = $compiler.frames.pop().unwrap(); + let frame = $compiler.current_context_mut().pop().unwrap(); // 0-th slot is the function itself. for var in frame.stack.iter().skip(1) { if !(var.read || var.upvalue) { @@ -311,13 +311,20 @@ impl Frame { } } +type CompilerContext = Vec; + +struct Section<'a> { + path: PathBuf, + tokens: &'a [PlacedToken], +} + pub(crate) struct Compiler<'a> { curr: usize, sections: Vec<&'a[PlacedToken]>, section: &'a[PlacedToken], current_file: PathBuf, - frames: Vec, + contextes: HashMap, panic: bool, errors: Vec, @@ -402,13 +409,16 @@ impl<'a> Compiler<'a> { let sections = split_sections(tokens); let section = sections[0]; + + let mut contextes = HashMap::new(); + contextes.insert(current_file.to_path_buf(), vec![Frame::new()]); Self { curr: 0, section, sections, current_file: PathBuf::from(current_file), - frames: vec![Frame::new()], + contextes, panic: false, errors: vec![], @@ -450,14 +460,22 @@ impl<'a> Compiler<'a> { self.strings.len() - 1 } + fn current_context(&self) -> &CompilerContext { + self.contextes.get(&self.current_file).unwrap() + } + + fn current_context_mut(&mut self) -> &mut CompilerContext { + self.contextes.get_mut(&self.current_file).unwrap() + } + fn frame(&self) -> &Frame { - let last = self.frames.len() - 1; - &self.frames[last] + let last = self.current_context().len() - 1; + &self.current_context()[last] } fn frame_mut(&mut self) -> &mut Frame { - let last = self.frames.len() - 1; - &mut self.frames[last] + let last = self.current_context().len() - 1; + &mut self.current_context_mut()[last] } /// Marks a variable as read. Also marks upvalues. @@ -468,15 +486,15 @@ impl<'a> Compiler<'a> { } - if if let Some(up) = self.frames[frame_id].upvalues.get(var.slot) { + if if let Some(up) = self.current_context()[frame_id].upvalues.get(var.slot) { up.name == var.name } else { false } { - let mut inner_var = self.frames[frame_id].upvalues[var.slot].clone(); + let mut inner_var = self.current_context()[frame_id].upvalues[var.slot].clone(); inner_var.slot = inner_var.outer_slot; self.mark_read(frame_id - 1, &inner_var); - self.frames[frame_id].upvalues[var.slot].read = true; + self.current_context_mut()[frame_id].upvalues[var.slot].read = true; } else { - self.frames[frame_id].stack[var.slot].read = true; + self.current_context_mut()[frame_id].stack[var.slot].read = true; } } @@ -780,7 +798,7 @@ impl<'a> Compiler<'a> { return Some(res); } - Self::find_and_capture_variable(name, self.frames.iter_mut().rev()) + Self::find_and_capture_variable(name, self.current_context_mut().iter_mut().rev()) } fn find_constant(&mut self, name: &str) -> usize { @@ -974,7 +992,7 @@ impl<'a> Compiler<'a> { // Variables if let Some(var) = self.find_variable(&name) { - self.mark_read(self.frames.len() - 1, &var); + self.mark_read(self.current_context().len() - 1, &var); if var.upvalue { add_op(self, block, Op::ReadUpvalue(var.slot)); } else { @@ -1038,7 +1056,7 @@ impl<'a> Compiler<'a> { fn constant_statement(&mut self, name: &str, typ: Type, block: &mut Block) { // Magical global constants - if self.frames.len() <= 1 { + if self.current_context().len() <= 1 { if parse_branch!(self, block, self.function(block, Some(name))) { // Remove the function, since it's a constant and we already // added it. @@ -1338,7 +1356,7 @@ impl<'a> Compiler<'a> { _ => unreachable!(), }; if let Some(var) = self.find_variable(&name) { - self.mark_read(self.frames.len() - 1, &var); + self.mark_read(self.current_context().len() - 1, &var); if var.upvalue { add_op(self, block, Op::ReadUpvalue(var.slot)); } else { @@ -1544,7 +1562,7 @@ impl<'a> Compiler<'a> { } } - for var in self.frames.pop().unwrap().stack.iter().skip(1) { + for var in self.current_context_mut().pop().unwrap().stack.iter().skip(1) { if !(var.read || var.upvalue) { let e = ErrorKind::SyntaxError(var.line, Token::Identifier(var.name.clone())); let m = format!("Unused value '{}'.", var.name); diff --git a/src/lib.rs b/src/lib.rs index 69bb66e..97f555c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,10 +20,11 @@ mod tokenizer; /// Compiles a file and links the supplied functions as callable external /// functions. Use this if you want your programs to be able to yield. -pub fn compile_file(path: &Path, - print: bool, - functions: Vec<(String, RustFunction)> - ) -> Result> { +pub fn compile_file( + path: &Path, + print: bool, + functions: Vec<(String, RustFunction)> +) -> Result> { let tokens = tokenizer::file_to_tokens(path); match compiler::Compiler::new(path, &tokens).compile("main", path, &functions) { Ok(prog) => { -- cgit v1.2.1 From f259d9e1f6490368766553c7e00f3292885c41ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Fri, 26 Feb 2021 18:55:12 +0100 Subject: store sections as structs containing their path --- src/compiler.rs | 69 ++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 41 insertions(+), 28 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index 5dae9ce..7d207e1 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -318,11 +318,19 @@ struct Section<'a> { tokens: &'a [PlacedToken], } +impl<'a> Section<'a> { + fn new(path: PathBuf, tokens: &'a [PlacedToken]) -> Self { + Section { + path, + tokens + } + } +} + pub(crate) struct Compiler<'a> { curr: usize, - sections: Vec<&'a[PlacedToken]>, - section: &'a[PlacedToken], - current_file: PathBuf, + current_section: usize, + sections: Vec>, contextes: HashMap, @@ -343,7 +351,7 @@ fn add_op(compiler: &Compiler, block: &mut Block, op: Op) -> usize { block.add(op, compiler.line()) } -fn split_sections<'a>(tokens: &'a TokenStream) -> Vec<&'a[PlacedToken]> { +fn split_sections<'a>(file_name: PathBuf, tokens: &'a TokenStream) -> Vec
{ let mut sections = Vec::new(); let mut last = 0; @@ -395,28 +403,26 @@ fn split_sections<'a>(tokens: &'a TokenStream) -> Vec<&'a[PlacedToken]> { _ => false, } { - sections.push(&tokens[last..curr]); + sections.push(Section::new(file_name.clone(), &tokens[last..curr])); last = curr; } curr += 1; } - sections.push(&tokens[last..curr]); + sections.push(Section::new(file_name, &tokens[last..curr])); sections } impl<'a> Compiler<'a> { pub(crate) fn new(current_file: &Path, tokens: &'a TokenStream) -> Self { - let sections = split_sections(tokens); - - let section = sections[0]; + let current_file = current_file.to_path_buf(); + let sections = split_sections(current_file.clone(), tokens); let mut contextes = HashMap::new(); - contextes.insert(current_file.to_path_buf(), vec![Frame::new()]); + contextes.insert(current_file, vec![Frame::new()]); Self { curr: 0, - section, + current_section: 0, sections, - current_file: PathBuf::from(current_file), contextes, @@ -460,12 +466,21 @@ impl<'a> Compiler<'a> { self.strings.len() - 1 } + fn section(&self) -> &Section { + &self.sections[self.current_section] + } + + fn current_file(&self) -> &Path { + &self.section().path + } + fn current_context(&self) -> &CompilerContext { - self.contextes.get(&self.current_file).unwrap() + self.contextes.get(self.current_file()).unwrap() } fn current_context_mut(&mut self) -> &mut CompilerContext { - self.contextes.get_mut(&self.current_file).unwrap() + let file = self.current_file().to_path_buf(); + self.contextes.get_mut(&file).unwrap() } fn frame(&self) -> &Frame { @@ -530,15 +545,15 @@ impl<'a> Compiler<'a> { self.panic = true; self.errors.push(Error { kind, - file: self.current_file.clone(), + file: self.current_file().to_path_buf(), line, message, }); } - fn init_section(&mut self, section: &'a[PlacedToken]) { + fn init_section(&mut self, section: usize) { self.curr = 0; - self.section = section; + self.current_section = section; } fn peek(&self) -> Token { @@ -546,10 +561,10 @@ impl<'a> Compiler<'a> { } fn peek_at(&self, at: usize) -> Token { - if self.section.len() <= self.curr + at { + if self.section().tokens.len() <= self.curr + at { crate::tokenizer::Token::EOF } else { - self.section[self.curr + at].0.clone() + self.section().tokens[self.curr + at].0.clone() } } @@ -578,10 +593,10 @@ impl<'a> Compiler<'a> { /// The line of the current token. fn line(&self) -> usize { - if self.section.len() == 0 { + if self.section().tokens.len() == 0 { 0xCAFEBABE } else { - self.section[std::cmp::min(self.curr, self.section.len() - 1)].1 + self.section().tokens[std::cmp::min(self.curr, self.section().tokens.len() - 1)].1 } } @@ -891,15 +906,15 @@ impl<'a> Compiler<'a> { self.stack_mut()[top].active = true; Cow::Borrowed(&self.stack()[top].name) } else { - Cow::Owned(format!("λ {}@{:03}", self.current_file.display(), self.line())) + Cow::Owned(format!("λ {}@{:03}", self.current_file().display(), self.line())) }; let mut args = Vec::new(); let mut return_type = Type::Void; - let mut function_block = Block::new(&name, &self.current_file); + 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); + 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, { @@ -1524,7 +1539,7 @@ impl<'a> Compiler<'a> { } - pub(crate) fn compile(&mut self, name: &str, file: &Path, functions: &[(String, RustFunction)]) -> Result> { + pub(crate) fn compile(&'a mut self, name: &str, file: &Path, functions: &[(String, RustFunction)]) -> Result> { self.functions = functions .to_vec() .into_iter() @@ -1536,11 +1551,9 @@ impl<'a> Compiler<'a> { let mut block = Block::new(name, file); for section in 0..self.sections.len() { - let s = section; - let section = self.sections[section]; self.init_section(section); while self.peek() != Token::EOF { - println!("compiling {} -- statement -- {:?}", s, self.line()); + println!("compiling {} -- statement -- {:?}", section, self.line()); self.statement(&mut block); expect!(self, Token::Newline | Token::EOF, "Expect newline or EOF after expression."); -- cgit v1.2.1 From 2d7bbe3a28a641e8ed915ff0f99cb308ec05c666 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Fri, 26 Feb 2021 19:08:44 +0100 Subject: curr -> current_token --- src/compiler.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index 7d207e1..32aa12b 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -43,7 +43,7 @@ macro_rules! parse_branch { ($compiler:expr, $block:expr, [ $( $call:expr ),* ]) => { { let block_length = $block.ops.len(); - let token_length = $compiler.curr; + let token_length = $compiler.current_token; let num_errors = $compiler.errors.len(); let mut stored_errors = Vec::new(); @@ -60,7 +60,7 @@ macro_rules! parse_branch { return true; } $compiler.panic = false; - $compiler.curr = token_length; + $compiler.current_token = token_length; let thrown_errors = $compiler.errors.len() - num_errors - 1; stored_errors.extend($compiler.errors.split_off(thrown_errors)); $block.ops.truncate(block_length); @@ -79,7 +79,7 @@ macro_rules! parse_branch { ($compiler:expr, $block:expr, $call:expr) => { { let block_length = $block.ops.len(); - let token_length = $compiler.curr; + let token_length = $compiler.current_token; let num_errors = $compiler.errors.len(); let mut stored_errors = Vec::new(); // Closures for early return on success. @@ -94,7 +94,7 @@ macro_rules! parse_branch { return true; } $compiler.panic = false; - $compiler.curr = token_length; + $compiler.current_token = token_length; let thrown_errors = $compiler.errors.len() - num_errors - 1; stored_errors.extend($compiler.errors.split_off(thrown_errors)); $block.ops.truncate(block_length); @@ -328,7 +328,7 @@ impl<'a> Section<'a> { } pub(crate) struct Compiler<'a> { - curr: usize, + current_token: usize, current_section: usize, sections: Vec>, @@ -420,7 +420,7 @@ impl<'a> Compiler<'a> { let mut contextes = HashMap::new(); contextes.insert(current_file, vec![Frame::new()]); Self { - curr: 0, + current_token: 0, current_section: 0, sections, @@ -552,7 +552,7 @@ impl<'a> Compiler<'a> { } fn init_section(&mut self, section: usize) { - self.curr = 0; + self.current_token = 0; self.current_section = section; } @@ -561,10 +561,10 @@ impl<'a> Compiler<'a> { } fn peek_at(&self, at: usize) -> Token { - if self.section().tokens.len() <= self.curr + at { + if self.section().tokens.len() <= self.current_token + at { crate::tokenizer::Token::EOF } else { - self.section().tokens[self.curr + at].0.clone() + self.section().tokens[self.current_token + at].0.clone() } } @@ -575,12 +575,12 @@ impl<'a> Compiler<'a> { fn eat(&mut self) -> Token { let t = self.peek(); - self.curr += 1; + self.current_token += 1; match t { Token::GitConflictBegin => { - self.curr -= 1; + self.current_token -= 1; let start = self.line(); - self.curr += 1; + self.current_token += 1; while !matches!(self.eat(), Token::GitConflictEnd) {} self.panic = false; self.error_on_line(ErrorKind::GitConflictError(start, self.line()), start, None); @@ -596,7 +596,7 @@ impl<'a> Compiler<'a> { if self.section().tokens.len() == 0 { 0xCAFEBABE } else { - self.section().tokens[std::cmp::min(self.curr, self.section().tokens.len() - 1)].1 + self.section().tokens[std::cmp::min(self.current_token, self.section().tokens.len() - 1)].1 } } -- cgit v1.2.1 From 538360aef838743be6e89409fe5653c7020dec97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Fri, 26 Feb 2021 20:36:11 +0100 Subject: some tests fail but we're almost there --- src/compiler.rs | 124 +++++++++++++++++++++++++++++++++++++++++++++++++------- src/lib.rs | 1 + 2 files changed, 111 insertions(+), 14 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index 680d1f1..76294d3 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -371,6 +371,14 @@ fn split_sections<'a>(file_name: PathBuf, tokens: &'a TokenStream) -> Vec { + if curr == last { + last += 1; + } + false + }, + (Some((Token::LeftBrace, _)), ..) => { let mut blocks = 0; @@ -617,7 +625,7 @@ impl<'a> Compiler<'a> { /// The line of the current token. fn line(&self) -> usize { if self.section().tokens.len() == 0 { - 0xCAFEBABE + unreachable!("An error occured without a section."); } else { self.section().tokens[std::cmp::min(self.current_token, self.section().tokens.len() - 1)].1 } @@ -878,6 +886,21 @@ impl<'a> Compiler<'a> { slot } + fn forward_constant(&mut self, name: String) -> usize { + let line = self.line(); + let slot = self.add_constant(Value::Unknown); + match self.names.entry(name.clone()) { + Entry::Occupied(_) => { + error!(self, format!("Constant named \"{}\" already has a value.", name)); + 0 + }, + Entry::Vacant(entry) => { + entry.insert(Name::Unknown(slot, line)); + slot + }, + } + } + fn call_maybe(&mut self, block: &mut Block) -> bool { if matches!(self.peek(), Token::Bang | Token::LeftParen) { self.call(block); @@ -1120,14 +1143,26 @@ impl<'a> Compiler<'a> { } fn definition_statement(&mut self, name: &str, typ: Type, block: &mut Block) { - let var = Variable::new(name, true, typ.clone()); - let slot = self.define(var); - self.expression(block); - let constant = self.add_constant(Value::Ty(typ)); - add_op(self, block, Op::Define(constant)); + if self.current_context().len() <= 1 { + // Global + let var = self.find_variable(name) + .expect(&format!("Couldn't find variable '{}' during prepass.", name)); + assert!(var.mutable); + + self.expression(block); + add_op(self, block, Op::AssignLocal(var.slot)); + self.stack_mut()[var.slot].active = true; + } else { + // Local + let var = Variable::new(name, true, typ.clone()); + let slot = self.define(var); + self.expression(block); + let constant = self.add_constant(Value::Ty(typ)); + add_op(self, block, Op::Define(constant)); - if let Ok(slot) = slot { - self.stack_mut()[slot].active = true; + if let Ok(slot) = slot { + self.stack_mut()[slot].active = true; + } } } @@ -1148,12 +1183,24 @@ impl<'a> Compiler<'a> { return; } - let var = Variable::new(name, false, typ); - let slot = self.define(var); - self.expression(block); + if self.current_context().len() <= 1 { + // Global + let var = self.find_variable(name) + .expect(&format!("Couldn't find constant '{}' during prepass.", name)); + assert!(var.mutable); - if let Ok(slot) = slot { - self.stack_mut()[slot].active = true; + self.expression(block); + add_op(self, block, Op::AssignLocal(var.slot)); + self.stack_mut()[var.slot].active = true; + } else { + // Local + let var = Variable::new(name, false, typ); + let slot = self.define(var); + self.expression(block); + + if let Ok(slot) = slot { + self.stack_mut()[slot].active = true; + } } } @@ -1590,6 +1637,56 @@ impl<'a> Compiler<'a> { } pub(crate) fn compile(&'a mut self, name: &str, file: &Path, functions: &[(String, RustFunction)]) -> Result> { + + for section in 0..self.sections.len() { + self.init_section(section); + let section = &self.sections[section]; + match (section.tokens.get(0), section.tokens.get(1), section.tokens.get(2)) { + (Some((Token::Identifier(name), _)), + Some((Token::ColonColon, _)), + Some((Token::Fn, _))) => { + self.forward_constant(name.to_string()); + }, + + (Some((Token::Blob, _)), + Some((Token::Identifier(name), _)), ..) => { + self.forward_constant(name.to_string()); + }, + + (Some((Token::Identifier(name), _)), + Some((Token::Colon, _)), ..) => { + self.eat(); + self.eat(); + if let Ok(ty) = self.parse_type() { + let is_mut = self.peek() == Token::Equal; + let var = Variable::new(name, is_mut, ty); + let _ = self.define(var); + } else { + error!(self, format!("Failed to parse type global '{}'.", name)); + } + } + + (Some((Token::Identifier(name), _)), + Some((Token::ColonColon, _)), ..) => { + let var = Variable::new(name, false, Type::Unknown); + let _ = self.define(var); + }, + + (Some((Token::Identifier(name), _)), + Some((Token::ColonEqual, _)), ..) => { + let var = Variable::new(name, true, Type::Unknown); + let _ = self.define(var); + }, + + + (None, ..) => {} + + (a, b, c) => { + panic!(format!("{:?} {:?} {:?}", a, b, c)); + } + } + } + self.functions = functions .to_vec() .into_iter() @@ -1603,7 +1700,6 @@ impl<'a> Compiler<'a> { for section in 0..self.sections.len() { self.init_section(section); while self.peek() != Token::EOF { - println!("compiling {} -- statement -- {:?}", section, self.line()); 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 9463c73..019d2d3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -928,6 +928,7 @@ mod tests { } #[test] + #[ignore = "Gives faulty line number"] fn assign_to_constant_upvalue() { assert_errs!(run_string("a :: 2\nq :: fn { a = 2 }\nq()\na", true, Vec::new()), [ErrorKind::SyntaxError(_, _)]); } -- cgit v1.2.1 From 48d73237d2ecab3827c50597f651f49ac4ca26b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Fri, 26 Feb 2021 20:44:08 +0100 Subject: add in start function --- src/compiler.rs | 45 +++++++++++++++++++++++++++++++++++++++++++-- src/lib.rs | 4 ++-- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index 76294d3..56a1d44 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -1529,6 +1529,44 @@ impl<'a> Compiler<'a> { } } + fn outer_statement(&mut self, block: &mut Block) { + self.clear_panic(); + match self.peek_four() { + (Token::Identifier(name), Token::ColonEqual, ..) => { + self.eat(); + self.eat(); + self.definition_statement(&name, Type::Unknown, block); + }, + + (Token::Identifier(name), Token::ColonColon, ..) => { + self.eat(); + self.eat(); + self.constant_statement(&name, Type::Unknown, block); + }, + + (Token::Blob, Token::Identifier(_), ..) => { + self.blob_statement(block); + }, + + (Token::Identifier(name), Token::Colon, ..) => { + self.eat(); + self.eat(); + if let Ok(typ) = self.parse_type() { + expect!(self, Token::Equal, "Expected assignment."); + self.definition_statement(&name, typ, block); + } else { + error!(self, format!("Expected type found '{:?}'.", self.peek())); + } + } + + (Token::Newline, ..) => {} + + _ => { + error!(self, "Invalid outer statement."); + } + } + } + fn statement(&mut self, block: &mut Block) { self.clear_panic(); @@ -1700,7 +1738,7 @@ impl<'a> Compiler<'a> { for section in 0..self.sections.len() { self.init_section(section); while self.peek() != Token::EOF { - self.statement(&mut block); + self.outer_statement(&mut block); expect!(self, Token::Newline | Token::EOF, "Expect newline or EOF after expression."); } @@ -1710,7 +1748,6 @@ impl<'a> Compiler<'a> { add_op(self, &mut block, Op::Return); block.ty = Type::Function(Vec::new(), Box::new(Type::Void)); - println!("{:?}", self.names); if self.names.len() != 0 { let errors: Vec<_> = self.names.iter().filter_map(|(name, kind)| if let Name::Unknown(_, line) = kind { @@ -1725,6 +1762,10 @@ impl<'a> Compiler<'a> { } } + let constant = self.find_constant("start"); + add_op(self, &mut block, Op::Constant(constant)); + add_op(self, &mut block, Op::Call(0)); + for var in self.current_context_mut().pop().unwrap().stack.iter().skip(1) { if !(var.read || var.upvalue) { let e = ErrorKind::SyntaxError(var.line, Token::Identifier(var.name.clone())); diff --git a/src/lib.rs b/src/lib.rs index 019d2d3..19ee8d7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -881,7 +881,7 @@ mod tests { #[test] fn $fn() { crate::tests::panic_after(std::time::Duration::from_millis(500), || { - let prog = std::concat!("q :: fn {", $prog, "\n{}\n}\nq()"); + let prog = std::concat!("start :: fn {", $prog, "\n{}\n}\n"); match $crate::run_string(&prog, true, Vec::new()) { Ok(()) => {}, Err(errs) => { @@ -899,7 +899,7 @@ mod tests { #[test] fn $fn() { crate::tests::panic_after(std::time::Duration::from_millis(500), || { - let prog = std::concat!("q :: fn {", $prog, "\n{}\n}\nq()"); + let prog = std::concat!("start :: fn {", $prog, "\n{}\n}\n"); $crate::assert_errs!($crate::run_string(&prog, true, Vec::new()), $errs); }) } -- cgit v1.2.1 From ba39d232db23c2ceb031fce613b377581d8b37b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Fri, 26 Feb 2021 20:50:11 +0100 Subject: Revert "FIXME comment out failing tests" This reverts commit 064bd91e7ceadde5272bf27fde59b43c27372cd3. --- src/lib.rs | 44 +++++++++++++++++--------------------------- 1 file changed, 17 insertions(+), 27 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 19ee8d7..4d669d8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1063,7 +1063,6 @@ a } add(1, 1) <=> 2 add(10, 20) <=> 30", - /* calls_inside_calls: "one := fn -> int { ret 1 } @@ -1087,7 +1086,6 @@ a ret inner(a) } f(g, 2) <=> 4", - */ multiple_returns: "f := fn a: int -> int { if a == 1 { ret 2 @@ -1114,7 +1112,6 @@ a factorial(6) <=> 720 factorial(12) <=> 479001600", -/* returning_closures: " f : fn -> fn -> int = fn -> fn -> int { x : int = 0 @@ -1137,17 +1134,15 @@ b() <=> 3 a() <=> 4 ", -*/ ); test_multiple!( blob, simple: "blob A {}", - field: "blob A { a: int }", - /* instantiate: "blob A {} a := A() a", + field: "blob A { a: int }", field_assign: "blob A { a: int } a := A() a.a = 2", @@ -1165,7 +1160,6 @@ a() <=> 4 a.b = 3 a.a + a.b <=> 5 5 <=> a.a + a.b", - */ blob_infer: " blob A { } a : A = A() @@ -1182,7 +1176,7 @@ a ); test_file!(scoping, "progs/tests/scoping.sy"); - // test_file!(for_, "progs/tests/for.sy"); + test_file!(for_, "progs/tests/for.sy"); test_multiple!( op_assign, @@ -1190,7 +1184,6 @@ a sub: "a := 2\na -= 1\na <=> 1", mul: "a := 2\na *= 2\na <=> 4", div: "a := 2\na /= 2\na <=> 1", -/* cluster: " blob A { a: int } a := A() @@ -1203,7 +1196,6 @@ a.a /= 2 a.a <=> 1 a.a -= 1 a.a <=> 0" -*/ ); test_multiple!( @@ -1369,7 +1361,6 @@ a ", -/* constant_function: " a() a :: fn {} @@ -1394,6 +1385,21 @@ q :: fn -> int { ret k() } ", + + constant_function_closure: " +q := 1 + +f :: fn -> int { + q += 1 + ret q +} + +f() <=> 2 +f() <=> 3 +f() <=> 4 +f() <=> 5 +", + constants_in_inner_functions: " q : int = 0 @@ -1412,24 +1418,9 @@ q <=> 2 g() q <=> 3 ", -*/ - - constant_function_closure: " -q := 1 -f :: fn -> int { - q += 1 - ret q -} - -f() <=> 2 -f() <=> 3 -f() <=> 4 -f() <=> 5 -", ); -/* test_string!(conflict_markers, " <<<<<<< HEAD print extern_test(4.0) @@ -1439,6 +1430,5 @@ print extern_test(5.0) ", [ErrorKind::SyntaxError(_, _), ErrorKind::GitConflictError(2, 6)] ); -*/ } -- cgit v1.2.1 From bd703c481822d0c3bf310a226e6a12b9579238e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Fri, 26 Feb 2021 20:50:37 +0100 Subject: unignore test --- src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 4d669d8..8a023b6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -928,7 +928,6 @@ mod tests { } #[test] - #[ignore = "Gives faulty line number"] fn assign_to_constant_upvalue() { assert_errs!(run_string("a :: 2\nq :: fn { a = 2 }\nq()\na", true, Vec::new()), [ErrorKind::SyntaxError(_, _)]); } -- cgit v1.2.1 From a5ad04378db7c0ef98d365f86c9fa7a6903b92b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Sun, 28 Feb 2021 13:49:04 +0100 Subject: return AFTER we call main --- src/compiler.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index 56a1d44..f4c369f 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -1743,9 +1743,6 @@ impl<'a> Compiler<'a> { "Expect newline or EOF after expression."); } } - let tmp = self.add_constant(Value::Unknown); - add_op(self, &mut block, Op::Constant(tmp)); - add_op(self, &mut block, Op::Return); block.ty = Type::Function(Vec::new(), Box::new(Type::Void)); if self.names.len() != 0 { @@ -1766,6 +1763,10 @@ impl<'a> Compiler<'a> { add_op(self, &mut block, Op::Constant(constant)); add_op(self, &mut block, Op::Call(0)); + let tmp = self.add_constant(Value::Unknown); + add_op(self, &mut block, Op::Constant(tmp)); + add_op(self, &mut block, Op::Return); + for var in self.current_context_mut().pop().unwrap().stack.iter().skip(1) { if !(var.read || var.upvalue) { let e = ErrorKind::SyntaxError(var.line, Token::Identifier(var.name.clone())); -- cgit v1.2.1 From 0a6133c7bae921ba35f2cd6a6594fed88f46e23a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Sun, 28 Feb 2021 14:57:50 +0100 Subject: start work on importing files --- src/compiler.rs | 197 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 111 insertions(+), 86 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index f4c369f..9113b19 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -51,16 +51,16 @@ macro_rules! parse_branch { let mut stored_errors = Vec::new(); // Closures for early return on success. - let success = (|| { + let success = loop { // We risk getting a lot of errors if we are in an invalid state // when we start the parse. if $compiler.panic { - return false; + break false; } $( $call; if !$compiler.panic { - return true; + break true; } $compiler.panic = false; $compiler.current_token = token_length; @@ -68,8 +68,8 @@ macro_rules! parse_branch { stored_errors.extend($compiler.errors.split_off(thrown_errors)); $block.ops.truncate(block_length); )* - false - })(); + break false; + }; if !success { $compiler.errors.extend(stored_errors); @@ -86,23 +86,23 @@ macro_rules! parse_branch { let num_errors = $compiler.errors.len(); let mut stored_errors = Vec::new(); // Closures for early return on success. - (|| { + loop { // We risk getting a lot of errors if we are in an invalid state // when we start the parse. if $compiler.panic { - return false; + break false; } $call; if !$compiler.panic { - return true; + break true; } $compiler.panic = false; $compiler.current_token = token_length; let thrown_errors = $compiler.errors.len() - num_errors - 1; stored_errors.extend($compiler.errors.split_off(thrown_errors)); $block.ops.truncate(block_length); - false - })() + break false; + } } }; } @@ -110,7 +110,7 @@ macro_rules! parse_branch { macro_rules! push_frame { ($compiler:expr, $block:expr, $code:tt) => { { - $compiler.current_context_mut().push(Frame::new()); + $compiler.frames_mut().push(Frame::new()); // Return value stored as a variable let var = Variable::new("", true, Type::Unknown); @@ -118,7 +118,7 @@ macro_rules! push_frame { $code - let frame = $compiler.current_context_mut().pop().unwrap(); + let frame = $compiler.frames_mut().pop().unwrap(); // 0-th slot is the function itself. for var in frame.stack.iter().skip(1) { if !(var.read || var.upvalue) { @@ -314,7 +314,21 @@ impl Frame { } } -type CompilerContext = Vec; +type Namespace<'a> = HashMap>; + +struct CompilerContext<'a> { + frames: Vec, + namespace: Namespace<'a>, +} + +impl<'a> CompilerContext<'a> { + fn new() -> Self { + Self { + frames: vec![Frame::new()], + namespace: Namespace::new(), + } + } +} struct Section<'a> { path: PathBuf, @@ -325,16 +339,16 @@ impl<'a> Section<'a> { fn new(path: PathBuf, tokens: &'a [PlacedToken]) -> Self { Section { path, - tokens + tokens, } } } #[derive(Debug)] -enum Name { +enum Name<'a> { Slot(usize, usize), Unknown(usize, usize), - Space(HashMap), + Namespace(&'a Namespace<'a>), } pub(crate) struct Compiler<'a> { @@ -342,7 +356,7 @@ pub(crate) struct Compiler<'a> { current_section: usize, sections: Vec>, - contextes: HashMap, + contextes: HashMap>, panic: bool, errors: Vec, @@ -356,7 +370,6 @@ pub(crate) struct Compiler<'a> { constants: Vec, values: HashMap, - names: HashMap, } /// Helper function for adding operations to the given block. @@ -439,7 +452,7 @@ impl<'a> Compiler<'a> { let sections = split_sections(current_file.clone(), tokens); let mut contextes = HashMap::new(); - contextes.insert(current_file, vec![Frame::new()]); + contextes.insert(current_file, CompilerContext::new()); Self { current_token: 0, current_section: 0, @@ -459,17 +472,16 @@ impl<'a> Compiler<'a> { constants: vec![], values: HashMap::new(), - names: HashMap::new(), } } - fn new_blob_id(&mut self) -> usize { + fn new_blob_id(&'a mut self) -> usize { let id = self.blob_id; self.blob_id += 1; id } - fn add_constant(&mut self, value: Value) -> usize { + fn add_constant(&'a mut self, value: Value) -> usize { if matches!(value, Value::Float(_) | Value::Int(_) | Value::Bool(_) @@ -492,7 +504,7 @@ impl<'a> Compiler<'a> { } } - fn intern_string(&mut self, string: String) -> usize { + fn intern_string(&'a mut self, string: String) -> usize { self.strings.push(string); self.strings.len() - 1 } @@ -509,38 +521,51 @@ impl<'a> Compiler<'a> { self.contextes.get(self.current_file()).unwrap() } - fn current_context_mut(&mut self) -> &mut CompilerContext { + fn current_context_mut(&'a mut self) -> &mut CompilerContext<'a> { let file = self.current_file().to_path_buf(); self.contextes.get_mut(&file).unwrap() } fn frame(&self) -> &Frame { - let last = self.current_context().len() - 1; - &self.current_context()[last] + self.current_context().frames.last().unwrap() + } + + fn frame_mut(&'a mut self) -> &mut Frame { + self.current_context_mut().frames.last_mut().unwrap() + } + + fn frames(&self) -> &[Frame] { + &self.current_context().frames } - fn frame_mut(&mut self) -> &mut Frame { - let last = self.current_context().len() - 1; - &mut self.current_context_mut()[last] + fn frames_mut(&'a mut self) -> &mut Vec { + &mut self.current_context_mut().frames + } + + fn names(&'a self) -> &Namespace<'a> { + &self.current_context().namespace + } + + fn names_mut(&'a mut self) -> &mut Namespace<'a> { + &mut self.current_context_mut().namespace } /// Marks a variable as read. Also marks upvalues. - fn mark_read(&mut self, frame_id: usize, var: &Variable) { + fn mark_read(&'a mut self, frame_id: usize, var: &Variable) { // Early out if var.read { return; } - - if if let Some(up) = self.current_context()[frame_id].upvalues.get(var.slot) { + if if let Some(up) = self.frames()[frame_id].upvalues.get(var.slot) { up.name == var.name } else { false } { - let mut inner_var = self.current_context()[frame_id].upvalues[var.slot].clone(); + let mut inner_var = self.frames()[frame_id].upvalues[var.slot].clone(); inner_var.slot = inner_var.outer_slot; self.mark_read(frame_id - 1, &inner_var); - self.current_context_mut()[frame_id].upvalues[var.slot].read = true; + self.frames_mut()[frame_id].upvalues[var.slot].read = true; } else { - self.current_context_mut()[frame_id].stack[var.slot].read = true; + self.frames_mut()[frame_id].stack[var.slot].read = true; } } @@ -548,12 +573,12 @@ impl<'a> Compiler<'a> { &self.frame().stack.as_ref() } - fn stack_mut(&mut self) -> &mut Vec { + fn stack_mut(&'a mut self) -> &mut Vec { &mut self.frame_mut().stack } /// Used to recover from a panic so the rest of the code can be parsed. - fn clear_panic(&mut self) { + fn clear_panic(&'a mut self) { if self.panic { self.panic = false; @@ -567,11 +592,11 @@ impl<'a> Compiler<'a> { } } - fn error(&mut self, kind: ErrorKind, message: Option) { + fn error(&'a mut self, kind: ErrorKind, message: Option) { self.error_on_line(kind, self.line(), message); } - fn error_on_line(&mut self, kind: ErrorKind, line: usize, message: Option) { + fn error_on_line(&'a mut self, kind: ErrorKind, line: usize, message: Option) { if self.panic { return } self.panic = true; self.errors.push(Error { @@ -582,7 +607,7 @@ impl<'a> Compiler<'a> { }); } - fn init_section(&mut self, section: usize) { + fn init_section(&'a mut self, section: usize) { self.current_token = 0; self.current_section = section; } @@ -604,7 +629,7 @@ impl<'a> Compiler<'a> { (self.peek_at(0), self.peek_at(1), self.peek_at(2), self.peek_at(3)) } - fn eat(&mut self) -> Token { + fn eat(&'a mut self) -> Token { let t = self.peek(); self.current_token += 1; match t { @@ -653,7 +678,7 @@ impl<'a> Compiler<'a> { } } - fn prefix(&mut self, token: Token, block: &mut Block) -> bool { + fn prefix(&'a mut self, token: Token, block: &mut Block) -> bool { match token { Token::Identifier(_) => self.variable_expression(block), Token::LeftParen => self.grouping_or_tuple(block), @@ -671,7 +696,7 @@ impl<'a> Compiler<'a> { return true; } - fn infix(&mut self, token: Token, block: &mut Block) -> bool { + fn infix(&'a mut self, token: Token, block: &mut Block) -> bool { match token { Token::Minus | Token::Plus @@ -693,7 +718,7 @@ impl<'a> Compiler<'a> { return true; } - fn value(&mut self, block: &mut Block) { + fn value(&'a mut self, block: &mut Block) { let value = match self.eat() { Token::Float(f) => { Value::Float(f) }, Token::Int(i) => { Value::Int(i) } @@ -705,11 +730,11 @@ impl<'a> Compiler<'a> { add_op(self, block, Op::Constant(constant)); } - fn grouping_or_tuple(&mut self, block: &mut Block) { + fn grouping_or_tuple(&'a mut self, block: &mut Block) { parse_branch!(self, block, [self.tuple(block), self.grouping(block)]); } - fn tuple(&mut self, block: &mut Block) { + fn tuple(&'a mut self, block: &mut Block) { expect!(self, Token::LeftParen, "Expected '(' at start of tuple"); let mut num_args = 0; @@ -744,7 +769,7 @@ impl<'a> Compiler<'a> { add_op(self, block, Op::Tuple(num_args)); } - fn grouping(&mut self, block: &mut Block) { + fn grouping(&'a mut self, block: &mut Block) { expect!(self, Token::LeftParen, "Expected '(' around expression."); self.expression(block); @@ -752,7 +777,7 @@ impl<'a> Compiler<'a> { expect!(self, Token::RightParen, "Expected ')' around expression."); } - fn index(&mut self, block: &mut Block) { + fn index(&'a mut self, block: &mut Block) { expect!(self, Token::LeftBracket, "Expected '[' around index."); self.expression(block); @@ -761,7 +786,7 @@ impl<'a> Compiler<'a> { expect!(self, Token::RightBracket, "Expected ']' around index."); } - fn unary(&mut self, block: &mut Block) { + fn unary(&'a mut self, block: &mut Block) { let op = match self.eat() { Token::Minus => Op::Neg, Token::Bang => Op::Not, @@ -771,7 +796,7 @@ impl<'a> Compiler<'a> { add_op(self, block, op); } - fn binary(&mut self, block: &mut Block) { + fn binary(&'a mut self, block: &mut Block) { let op = self.eat(); self.parse_precedence(block, self.precedence(op.clone()).next()); @@ -794,14 +819,14 @@ impl<'a> Compiler<'a> { } /// Entry point for all expression parsing. - fn expression(&mut self, block: &mut Block) { + fn expression(&'a mut self, block: &mut Block) { match self.peek_four() { (Token::Fn, ..) => { self.function(block, None); }, _ => self.parse_precedence(block, Prec::No), } } - fn parse_precedence(&mut self, block: &mut Block, precedence: Prec) { + fn parse_precedence(&'a mut self, block: &mut Block, precedence: Prec) { if !self.prefix(self.peek(), block) { error!(self, "Invalid expression."); } @@ -835,7 +860,7 @@ impl<'a> Compiler<'a> { self.functions.get(name).map(|(i, _)| *i) } - fn find_variable(&mut self, name: &str) -> Option { + fn find_variable(&'a mut self, name: &str) -> Option { if let Some(res) = self.frame().find_local(name) { return Some(res); } @@ -844,11 +869,11 @@ impl<'a> Compiler<'a> { return Some(res); } - Self::find_and_capture_variable(name, self.current_context_mut().iter_mut().rev()) + Self::find_and_capture_variable(name, self.frames_mut().iter_mut().rev()) } - fn find_constant(&mut self, name: &str) -> usize { - match self.names.entry(name.to_string()) { + fn find_constant(&'a mut self, name: &str) -> usize { + match self.names().entry(name.to_string()) { Entry::Occupied(entry) => { match entry.get() { Name::Slot(i, _) => { return *i; }, @@ -861,13 +886,13 @@ impl<'a> Compiler<'a> { let slot = self.add_constant(Value::Unknown); let line = self.line(); - self.names.insert(name.to_string(), Name::Unknown(slot, line)); + self.names().insert(name.to_string(), Name::Unknown(slot, line)); slot } - fn named_constant(&mut self, name: String, value: Value) -> usize { + fn named_constant(&'a mut self, name: String, value: Value) -> usize { let line = self.line(); - match self.names.entry(name.clone()) { + match self.names().entry(name.clone()) { Entry::Occupied(mut entry) => { let slot = if let Name::Unknown(slot, _) = entry.get() { *slot @@ -882,14 +907,14 @@ impl<'a> Compiler<'a> { Entry::Vacant(_) => {}, } let slot = self.add_constant(value); - self.names.insert(name, Name::Slot(slot, line)); + self.names().insert(name, Name::Slot(slot, line)); slot } - fn forward_constant(&mut self, name: String) -> usize { + fn forward_constant(&'a mut self, name: String) -> usize { let line = self.line(); let slot = self.add_constant(Value::Unknown); - match self.names.entry(name.clone()) { + match self.names().entry(name.clone()) { Entry::Occupied(_) => { error!(self, format!("Constant named \"{}\" already has a value.", name)); 0 @@ -901,7 +926,7 @@ impl<'a> Compiler<'a> { } } - fn call_maybe(&mut self, block: &mut Block) -> bool { + fn call_maybe(&'a mut self, block: &mut Block) -> bool { if matches!(self.peek(), Token::Bang | Token::LeftParen) { self.call(block); true @@ -910,7 +935,7 @@ impl<'a> Compiler<'a> { } } - fn call(&mut self, block: &mut Block) { + fn call(&'a mut self, block: &mut Block) { let mut arity = 0; match self.peek() { Token::LeftParen => { @@ -975,7 +1000,7 @@ impl<'a> Compiler<'a> { } // TODO(ed): de-complexify - fn function(&mut self, block: &mut Block, in_name: Option<&str>) { + fn function(&'a mut self, block: &mut Block, in_name: Option<&str>) { expect!(self, Token::Fn, "Expected 'fn' at start of function."); let top = self.stack().len() - 1; @@ -1076,7 +1101,7 @@ impl<'a> Compiler<'a> { add_op(self, block, Op::Constant(constant)); } - fn variable_expression(&mut self, block: &mut Block) { + fn variable_expression(&'a mut self, block: &mut Block) { let name = match self.eat() { Token::Identifier(name) => name, _ => unreachable!(), @@ -1092,7 +1117,7 @@ impl<'a> Compiler<'a> { // Variables if let Some(var) = self.find_variable(&name) { - self.mark_read(self.current_context().len() - 1, &var); + self.mark_read(self.frames().len() - 1, &var); if var.upvalue { add_op(self, block, Op::ReadUpvalue(var.slot)); } else { @@ -1125,7 +1150,7 @@ impl<'a> Compiler<'a> { self.call_maybe(block); } - fn define(&mut self, mut var: Variable) -> Result { + fn define(&'a mut self, mut var: Variable) -> Result { if let Some(var) = self.find_variable(&var.name) { if var.scope == self.frame().scope { error!(self, format!("Multiple definitions of '{}' in this block.", @@ -1142,8 +1167,8 @@ impl<'a> Compiler<'a> { Ok(slot) } - fn definition_statement(&mut self, name: &str, typ: Type, block: &mut Block) { - if self.current_context().len() <= 1 { + fn definition_statement(&'a mut self, name: &str, typ: Type, block: &mut Block) { + if self.frames().len() <= 1 { // Global let var = self.find_variable(name) .expect(&format!("Couldn't find variable '{}' during prepass.", name)); @@ -1166,9 +1191,9 @@ impl<'a> Compiler<'a> { } } - fn constant_statement(&mut self, name: &str, typ: Type, block: &mut Block) { + fn constant_statement(&'a mut self, name: &str, typ: Type, block: &mut Block) { // Magical global constants - if self.current_context().len() <= 1 && self.peek() == Token::Fn { + if self.frames().len() <= 1 && self.peek() == Token::Fn { self.function(block, Some(name)); // Remove the function, since it's a constant and we already // added it. @@ -1183,7 +1208,7 @@ impl<'a> Compiler<'a> { return; } - if self.current_context().len() <= 1 { + if self.frames().len() <= 1 { // Global let var = self.find_variable(name) .expect(&format!("Couldn't find constant '{}' during prepass.", name)); @@ -1204,7 +1229,7 @@ impl<'a> Compiler<'a> { } } - fn assign(&mut self, block: &mut Block) { + fn assign(&'a mut self, block: &mut Block) { let name = match self.eat() { Token::Identifier(name) => name, _ => { @@ -1254,7 +1279,7 @@ impl<'a> Compiler<'a> { } } - fn scope(&mut self, block: &mut Block) { + fn scope(&'a mut self, block: &mut Block) { if !expect!(self, Token::LeftBrace, "Expected '{' at start of block.") { return; } @@ -1273,7 +1298,7 @@ impl<'a> Compiler<'a> { expect!(self, Token::RightBrace, "Expected '}' at end of block."); } - fn if_statment(&mut self, block: &mut Block) { + fn if_statment(&'a mut self, block: &mut Block) { expect!(self, Token::If, "Expected 'if' at start of if-statement."); self.expression(block); let jump = add_op(self, block, Op::Illegal); @@ -1297,7 +1322,7 @@ impl<'a> Compiler<'a> { } //TODO de-complexify - fn for_loop(&mut self, block: &mut Block) { + fn for_loop(&'a mut self, block: &mut Block) { expect!(self, Token::For, "Expected 'for' at start of for-loop."); push_scope!(self, block, { @@ -1342,7 +1367,7 @@ impl<'a> Compiler<'a> { }); } - fn parse_type(&mut self) -> Result { + fn parse_type(&'a mut self) -> Result { match self.peek() { Token::Fn => { @@ -1419,7 +1444,7 @@ impl<'a> Compiler<'a> { } } - fn blob_statement(&mut self, _block: &mut Block) { + fn blob_statement(&'a mut self, _block: &mut Block) { expect!(self, Token::Blob, "Expected blob when declaring a blob"); let name = if let Token::Identifier(name) = self.eat() { name @@ -1462,13 +1487,13 @@ impl<'a> Compiler<'a> { self.named_constant(name, blob); } - fn blob_field(&mut self, block: &mut Block) { + fn blob_field(&'a mut self, block: &mut Block) { let name = match self.eat() { Token::Identifier(name) => name, _ => unreachable!(), }; if let Some(var) = self.find_variable(&name) { - self.mark_read(self.current_context().len() - 1, &var); + self.mark_read(self.frames().len() - 1, &var); if var.upvalue { add_op(self, block, Op::ReadUpvalue(var.slot)); } else { @@ -1529,7 +1554,7 @@ impl<'a> Compiler<'a> { } } - fn outer_statement(&mut self, block: &mut Block) { + fn outer_statement(&'a mut self, block: &mut Block) { self.clear_panic(); match self.peek_four() { (Token::Identifier(name), Token::ColonEqual, ..) => { @@ -1567,7 +1592,7 @@ impl<'a> Compiler<'a> { } } - fn statement(&mut self, block: &mut Block) { + fn statement(&'a mut self, block: &mut Block) { self.clear_panic(); match self.peek_four() { @@ -1745,8 +1770,8 @@ impl<'a> Compiler<'a> { } block.ty = Type::Function(Vec::new(), Box::new(Type::Void)); - if self.names.len() != 0 { - let errors: Vec<_> = self.names.iter().filter_map(|(name, kind)| + if self.names().len() != 0 { + let errors: Vec<_> = self.names().iter().filter_map(|(name, kind)| if let Name::Unknown(_, line) = kind { Some((ErrorKind::SyntaxError(*line, Token::Identifier(name.clone())), *line, @@ -1767,7 +1792,7 @@ impl<'a> Compiler<'a> { add_op(self, &mut block, Op::Constant(tmp)); add_op(self, &mut block, Op::Return); - for var in self.current_context_mut().pop().unwrap().stack.iter().skip(1) { + for var in self.frames_mut().pop().unwrap().stack.iter().skip(1) { if !(var.read || var.upvalue) { let e = ErrorKind::SyntaxError(var.line, Token::Identifier(var.name.clone())); let m = format!("Unused value '{}'.", var.name); -- cgit v1.2.1 From dbf6d4136b8091471fffb9a6324642db11d8484f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Sun, 28 Feb 2021 16:02:28 +0100 Subject: new lifetime 'b --- src/compiler.rs | 129 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 65 insertions(+), 64 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index 9113b19..fc28b7d 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -446,7 +446,7 @@ fn split_sections<'a>(file_name: PathBuf, tokens: &'a TokenStream) -> Vec Compiler<'a> { +impl<'a, 'b> Compiler<'a> { pub(crate) fn new(current_file: &Path, tokens: &'a TokenStream) -> Self { let current_file = current_file.to_path_buf(); let sections = split_sections(current_file.clone(), tokens); @@ -475,13 +475,13 @@ impl<'a> Compiler<'a> { } } - fn new_blob_id(&'a mut self) -> usize { + fn new_blob_id(&'b mut self) -> usize { let id = self.blob_id; self.blob_id += 1; id } - fn add_constant(&'a mut self, value: Value) -> usize { + fn add_constant(&'b mut self, value: Value) -> usize { if matches!(value, Value::Float(_) | Value::Int(_) | Value::Bool(_) @@ -504,7 +504,7 @@ impl<'a> Compiler<'a> { } } - fn intern_string(&'a mut self, string: String) -> usize { + fn intern_string(&'b mut self, string: String) -> usize { self.strings.push(string); self.strings.len() - 1 } @@ -517,11 +517,11 @@ impl<'a> Compiler<'a> { &self.section().path } - fn current_context(&self) -> &CompilerContext { + fn current_context(&'b self) -> &CompilerContext { self.contextes.get(self.current_file()).unwrap() } - fn current_context_mut(&'a mut self) -> &mut CompilerContext<'a> { + fn current_context_mut(&'b mut self) -> &mut CompilerContext<'a> { let file = self.current_file().to_path_buf(); self.contextes.get_mut(&file).unwrap() } @@ -530,7 +530,7 @@ impl<'a> Compiler<'a> { self.current_context().frames.last().unwrap() } - fn frame_mut(&'a mut self) -> &mut Frame { + fn frame_mut(&'b mut self) -> &mut Frame { self.current_context_mut().frames.last_mut().unwrap() } @@ -538,7 +538,7 @@ impl<'a> Compiler<'a> { &self.current_context().frames } - fn frames_mut(&'a mut self) -> &mut Vec { + fn frames_mut(&'b mut self) -> &mut Vec { &mut self.current_context_mut().frames } @@ -546,26 +546,27 @@ impl<'a> Compiler<'a> { &self.current_context().namespace } - fn names_mut(&'a mut self) -> &mut Namespace<'a> { + fn names_mut(&'b mut self) -> &mut Namespace<'a> { &mut self.current_context_mut().namespace } /// Marks a variable as read. Also marks upvalues. - fn mark_read(&'a mut self, frame_id: usize, var: &Variable) { + fn mark_read(&'b mut self, frame_id: usize, var: &Variable) { // Early out if var.read { return; } - if if let Some(up) = self.frames()[frame_id].upvalues.get(var.slot) { - up.name == var.name - } else { false } { - let mut inner_var = self.frames()[frame_id].upvalues[var.slot].clone(); - inner_var.slot = inner_var.outer_slot; - self.mark_read(frame_id - 1, &inner_var); - self.frames_mut()[frame_id].upvalues[var.slot].read = true; - } else { - self.frames_mut()[frame_id].stack[var.slot].read = true; + match self.frames()[frame_id].upvalues.get(var.slot) { + Some(up) if up.name == var.name => { + let mut inner_var = self.frames()[frame_id].upvalues[var.slot].clone(); + inner_var.slot = inner_var.outer_slot; + self.mark_read(frame_id - 1, &inner_var); + self.frames_mut()[frame_id].upvalues[var.slot].read = true; + } + _ => { + self.frames_mut()[frame_id].stack[var.slot].read = true; + } } } @@ -573,12 +574,12 @@ impl<'a> Compiler<'a> { &self.frame().stack.as_ref() } - fn stack_mut(&'a mut self) -> &mut Vec { + fn stack_mut(&'b mut self) -> &mut Vec { &mut self.frame_mut().stack } /// Used to recover from a panic so the rest of the code can be parsed. - fn clear_panic(&'a mut self) { + fn clear_panic(&'b mut self) { if self.panic { self.panic = false; @@ -592,11 +593,11 @@ impl<'a> Compiler<'a> { } } - fn error(&'a mut self, kind: ErrorKind, message: Option) { + fn error(&'b mut self, kind: ErrorKind, message: Option) { self.error_on_line(kind, self.line(), message); } - fn error_on_line(&'a mut self, kind: ErrorKind, line: usize, message: Option) { + fn error_on_line(&'b mut self, kind: ErrorKind, line: usize, message: Option) { if self.panic { return } self.panic = true; self.errors.push(Error { @@ -607,7 +608,7 @@ impl<'a> Compiler<'a> { }); } - fn init_section(&'a mut self, section: usize) { + fn init_section(&'b mut self, section: usize) { self.current_token = 0; self.current_section = section; } @@ -629,7 +630,7 @@ impl<'a> Compiler<'a> { (self.peek_at(0), self.peek_at(1), self.peek_at(2), self.peek_at(3)) } - fn eat(&'a mut self) -> Token { + fn eat(&'b mut self) -> Token { let t = self.peek(); self.current_token += 1; match t { @@ -678,7 +679,7 @@ impl<'a> Compiler<'a> { } } - fn prefix(&'a mut self, token: Token, block: &mut Block) -> bool { + fn prefix(&'b mut self, token: Token, block: &mut Block) -> bool { match token { Token::Identifier(_) => self.variable_expression(block), Token::LeftParen => self.grouping_or_tuple(block), @@ -696,7 +697,7 @@ impl<'a> Compiler<'a> { return true; } - fn infix(&'a mut self, token: Token, block: &mut Block) -> bool { + fn infix(&'b mut self, token: Token, block: &mut Block) -> bool { match token { Token::Minus | Token::Plus @@ -718,7 +719,7 @@ impl<'a> Compiler<'a> { return true; } - fn value(&'a mut self, block: &mut Block) { + fn value(&'b mut self, block: &mut Block) { let value = match self.eat() { Token::Float(f) => { Value::Float(f) }, Token::Int(i) => { Value::Int(i) } @@ -730,11 +731,11 @@ impl<'a> Compiler<'a> { add_op(self, block, Op::Constant(constant)); } - fn grouping_or_tuple(&'a mut self, block: &mut Block) { + fn grouping_or_tuple(&'b mut self, block: &mut Block) { parse_branch!(self, block, [self.tuple(block), self.grouping(block)]); } - fn tuple(&'a mut self, block: &mut Block) { + fn tuple(&'b mut self, block: &mut Block) { expect!(self, Token::LeftParen, "Expected '(' at start of tuple"); let mut num_args = 0; @@ -769,7 +770,7 @@ impl<'a> Compiler<'a> { add_op(self, block, Op::Tuple(num_args)); } - fn grouping(&'a mut self, block: &mut Block) { + fn grouping(&'b mut self, block: &mut Block) { expect!(self, Token::LeftParen, "Expected '(' around expression."); self.expression(block); @@ -777,7 +778,7 @@ impl<'a> Compiler<'a> { expect!(self, Token::RightParen, "Expected ')' around expression."); } - fn index(&'a mut self, block: &mut Block) { + fn index(&'b mut self, block: &mut Block) { expect!(self, Token::LeftBracket, "Expected '[' around index."); self.expression(block); @@ -786,7 +787,7 @@ impl<'a> Compiler<'a> { expect!(self, Token::RightBracket, "Expected ']' around index."); } - fn unary(&'a mut self, block: &mut Block) { + fn unary(&'b mut self, block: &mut Block) { let op = match self.eat() { Token::Minus => Op::Neg, Token::Bang => Op::Not, @@ -796,7 +797,7 @@ impl<'a> Compiler<'a> { add_op(self, block, op); } - fn binary(&'a mut self, block: &mut Block) { + fn binary(&'b mut self, block: &mut Block) { let op = self.eat(); self.parse_precedence(block, self.precedence(op.clone()).next()); @@ -819,14 +820,14 @@ impl<'a> Compiler<'a> { } /// Entry point for all expression parsing. - fn expression(&'a mut self, block: &mut Block) { + fn expression(&'b mut self, block: &mut Block) { match self.peek_four() { (Token::Fn, ..) => { self.function(block, None); }, _ => self.parse_precedence(block, Prec::No), } } - fn parse_precedence(&'a mut self, block: &mut Block, precedence: Prec) { + fn parse_precedence(&'b mut self, block: &mut Block, precedence: Prec) { if !self.prefix(self.peek(), block) { error!(self, "Invalid expression."); } @@ -838,8 +839,8 @@ impl<'a> Compiler<'a> { } } - fn find_and_capture_variable<'b, I>(name: &str, mut iterator: I) -> Option - where I: Iterator { + fn find_and_capture_variable<'i, 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; @@ -860,7 +861,7 @@ impl<'a> Compiler<'a> { self.functions.get(name).map(|(i, _)| *i) } - fn find_variable(&'a mut self, name: &str) -> Option { + fn find_variable(&'b mut self, name: &str) -> Option { if let Some(res) = self.frame().find_local(name) { return Some(res); } @@ -872,8 +873,8 @@ impl<'a> Compiler<'a> { Self::find_and_capture_variable(name, self.frames_mut().iter_mut().rev()) } - fn find_constant(&'a mut self, name: &str) -> usize { - match self.names().entry(name.to_string()) { + fn find_constant(&'b mut self, name: &str) -> usize { + match self.names_mut().entry(name.to_string()) { Entry::Occupied(entry) => { match entry.get() { Name::Slot(i, _) => { return *i; }, @@ -886,13 +887,13 @@ impl<'a> Compiler<'a> { let slot = self.add_constant(Value::Unknown); let line = self.line(); - self.names().insert(name.to_string(), Name::Unknown(slot, line)); + self.names_mut().insert(name.to_string(), Name::Unknown(slot, line)); slot } - fn named_constant(&'a mut self, name: String, value: Value) -> usize { + fn named_constant(&'b mut self, name: String, value: Value) -> usize { let line = self.line(); - match self.names().entry(name.clone()) { + match self.names_mut().entry(name.clone()) { Entry::Occupied(mut entry) => { let slot = if let Name::Unknown(slot, _) = entry.get() { *slot @@ -907,14 +908,14 @@ impl<'a> Compiler<'a> { Entry::Vacant(_) => {}, } let slot = self.add_constant(value); - self.names().insert(name, Name::Slot(slot, line)); + self.names_mut().insert(name, Name::Slot(slot, line)); slot } - fn forward_constant(&'a mut self, name: String) -> usize { + fn forward_constant(&'b mut self, name: String) -> usize { let line = self.line(); let slot = self.add_constant(Value::Unknown); - match self.names().entry(name.clone()) { + match self.names_mut().entry(name.clone()) { Entry::Occupied(_) => { error!(self, format!("Constant named \"{}\" already has a value.", name)); 0 @@ -926,7 +927,7 @@ impl<'a> Compiler<'a> { } } - fn call_maybe(&'a mut self, block: &mut Block) -> bool { + fn call_maybe(&'b mut self, block: &mut Block) -> bool { if matches!(self.peek(), Token::Bang | Token::LeftParen) { self.call(block); true @@ -935,7 +936,7 @@ impl<'a> Compiler<'a> { } } - fn call(&'a mut self, block: &mut Block) { + fn call(&'b mut self, block: &mut Block) { let mut arity = 0; match self.peek() { Token::LeftParen => { @@ -1000,7 +1001,7 @@ impl<'a> Compiler<'a> { } // TODO(ed): de-complexify - fn function(&'a mut self, block: &mut Block, in_name: Option<&str>) { + fn function(&'b mut self, block: &mut Block, in_name: Option<&str>) { expect!(self, Token::Fn, "Expected 'fn' at start of function."); let top = self.stack().len() - 1; @@ -1101,7 +1102,7 @@ impl<'a> Compiler<'a> { add_op(self, block, Op::Constant(constant)); } - fn variable_expression(&'a mut self, block: &mut Block) { + fn variable_expression(&'b mut self, block: &mut Block) { let name = match self.eat() { Token::Identifier(name) => name, _ => unreachable!(), @@ -1150,7 +1151,7 @@ impl<'a> Compiler<'a> { self.call_maybe(block); } - fn define(&'a mut self, mut var: Variable) -> Result { + fn define(&'b mut self, mut var: Variable) -> Result { if let Some(var) = self.find_variable(&var.name) { if var.scope == self.frame().scope { error!(self, format!("Multiple definitions of '{}' in this block.", @@ -1167,7 +1168,7 @@ impl<'a> Compiler<'a> { Ok(slot) } - fn definition_statement(&'a mut self, name: &str, typ: Type, block: &mut Block) { + fn definition_statement(&'b mut self, name: &str, typ: Type, block: &mut Block) { if self.frames().len() <= 1 { // Global let var = self.find_variable(name) @@ -1191,7 +1192,7 @@ impl<'a> Compiler<'a> { } } - fn constant_statement(&'a mut self, name: &str, typ: Type, block: &mut Block) { + fn constant_statement(&'b mut self, name: &str, typ: Type, block: &mut Block) { // Magical global constants if self.frames().len() <= 1 && self.peek() == Token::Fn { self.function(block, Some(name)); @@ -1229,7 +1230,7 @@ impl<'a> Compiler<'a> { } } - fn assign(&'a mut self, block: &mut Block) { + fn assign(&'b mut self, block: &mut Block) { let name = match self.eat() { Token::Identifier(name) => name, _ => { @@ -1279,7 +1280,7 @@ impl<'a> Compiler<'a> { } } - fn scope(&'a mut self, block: &mut Block) { + fn scope(&'b mut self, block: &mut Block) { if !expect!(self, Token::LeftBrace, "Expected '{' at start of block.") { return; } @@ -1298,7 +1299,7 @@ impl<'a> Compiler<'a> { expect!(self, Token::RightBrace, "Expected '}' at end of block."); } - fn if_statment(&'a mut self, block: &mut Block) { + fn if_statment(&'b mut self, block: &mut Block) { expect!(self, Token::If, "Expected 'if' at start of if-statement."); self.expression(block); let jump = add_op(self, block, Op::Illegal); @@ -1322,7 +1323,7 @@ impl<'a> Compiler<'a> { } //TODO de-complexify - fn for_loop(&'a mut self, block: &mut Block) { + fn for_loop(&'b mut self, block: &mut Block) { expect!(self, Token::For, "Expected 'for' at start of for-loop."); push_scope!(self, block, { @@ -1367,7 +1368,7 @@ impl<'a> Compiler<'a> { }); } - fn parse_type(&'a mut self) -> Result { + fn parse_type(&'b mut self) -> Result { match self.peek() { Token::Fn => { @@ -1444,7 +1445,7 @@ impl<'a> Compiler<'a> { } } - fn blob_statement(&'a mut self, _block: &mut Block) { + fn blob_statement(&'b mut self, _block: &mut Block) { expect!(self, Token::Blob, "Expected blob when declaring a blob"); let name = if let Token::Identifier(name) = self.eat() { name @@ -1487,7 +1488,7 @@ impl<'a> Compiler<'a> { self.named_constant(name, blob); } - fn blob_field(&'a mut self, block: &mut Block) { + fn blob_field(&'b mut self, block: &mut Block) { let name = match self.eat() { Token::Identifier(name) => name, _ => unreachable!(), @@ -1554,7 +1555,7 @@ impl<'a> Compiler<'a> { } } - fn outer_statement(&'a mut self, block: &mut Block) { + fn outer_statement(&'b mut self, block: &mut Block) { self.clear_panic(); match self.peek_four() { (Token::Identifier(name), Token::ColonEqual, ..) => { @@ -1592,7 +1593,7 @@ impl<'a> Compiler<'a> { } } - fn statement(&'a mut self, block: &mut Block) { + fn statement(&'b mut self, block: &mut Block) { self.clear_panic(); match self.peek_four() { @@ -1699,7 +1700,7 @@ impl<'a> Compiler<'a> { } - pub(crate) fn compile(&'a mut self, name: &str, file: &Path, functions: &[(String, RustFunction)]) -> Result> { + pub(crate) fn compile(&'b mut self, name: &str, file: &Path, functions: &[(String, RustFunction)]) -> Result> { for section in 0..self.sections.len() { self.init_section(section); -- cgit v1.2.1 From c3e1e3bcbb177a5cbdb972389626e8c7347cbfc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Sun, 28 Feb 2021 17:23:09 +0100 Subject: move sectionizer, sections own tokens --- src/compiler.rs | 112 ++++++++--------------------------------------------- src/lib.rs | 51 +++++++++++------------- src/sectionizer.rs | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/tokenizer.rs | 3 ++ 4 files changed, 150 insertions(+), 125 deletions(-) create mode 100644 src/sectionizer.rs diff --git a/src/compiler.rs b/src/compiler.rs index fc28b7d..90bc51e 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -1,11 +1,12 @@ -use std::{path::{Path, PathBuf}}; +use std::path::{Path, PathBuf}; use std::cell::RefCell; use std::collections::{HashMap, hash_map::Entry}; use std::rc::Rc; use crate::{Blob, Block, Op, Prog, RustFunction, Type, Value}; use crate::error::{Error, ErrorKind}; -use crate::tokenizer::{Token, PlacedToken, TokenStream}; +use crate::sectionizer::Section; +use crate::tokenizer::Token; macro_rules! nextable_enum { ( $name:ident { $( $thing:ident ),* $( , )? } ) => { @@ -330,31 +331,17 @@ impl<'a> CompilerContext<'a> { } } -struct Section<'a> { - path: PathBuf, - tokens: &'a [PlacedToken], -} - -impl<'a> Section<'a> { - fn new(path: PathBuf, tokens: &'a [PlacedToken]) -> Self { - Section { - path, - tokens, - } - } -} - #[derive(Debug)] enum Name<'a> { Slot(usize, usize), Unknown(usize, usize), - Namespace(&'a Namespace<'a>), + _Namespace(&'a Namespace<'a>), } pub(crate) struct Compiler<'a> { current_token: usize, current_section: usize, - sections: Vec>, + sections: Vec
, contextes: HashMap>, @@ -377,82 +364,13 @@ fn add_op(compiler: &Compiler, block: &mut Block, op: Op) -> usize { block.add(op, compiler.line()) } -fn split_sections<'a>(file_name: PathBuf, tokens: &'a TokenStream) -> Vec
{ - let mut sections = Vec::new(); - - let mut last = 0; - let mut curr = 0; - while curr < tokens.len() { - if match (tokens.get(curr + 0), tokens.get(curr + 1), tokens.get(curr + 2)) { - (Some((Token::Newline, _)), ..) - => { - if curr == last { - last += 1; - } - false - }, - - (Some((Token::LeftBrace, _)), ..) - => { - let mut blocks = 0; - loop { - curr += 1; - match tokens.get(curr) { - Some((Token::LeftBrace, _)) => { - blocks += 1; - } - - Some((Token::RightBrace, _)) => { - curr += 1; - blocks -= 1; - if blocks <= 0 { - break; - } - } - - None => { - break; - } - - _ => {} - } - } - false - }, - - (Some((Token::Identifier(_), _)), - Some((Token::ColonColon, _)), - Some((Token::Fn, _))) - => true, - - (Some((Token::Identifier(_), _)), - Some((Token::ColonColon, _)), - Some(_)) - => true, - - (Some((Token::Identifier(_), _)), - Some((Token::ColonEqual, _)), - Some(_)) - => true, - - _ => false, - } { - sections.push(Section::new(file_name.clone(), &tokens[last..curr])); - last = curr; - } - curr += 1; - } - sections.push(Section::new(file_name, &tokens[last..curr])); - sections -} - impl<'a, 'b> Compiler<'a> { - pub(crate) fn new(current_file: &Path, tokens: &'a TokenStream) -> Self { - let current_file = current_file.to_path_buf(); - let sections = split_sections(current_file.clone(), tokens); + pub(crate) fn new(sections: Vec
) -> Self { + let contextes = sections + .iter() + .map(|section| (section.path.to_path_buf(), CompilerContext::new())) + .collect(); - let mut contextes = HashMap::new(); - contextes.insert(current_file, CompilerContext::new()); Self { current_token: 0, current_section: 0, @@ -1701,7 +1619,6 @@ impl<'a, 'b> Compiler<'a> { } pub(crate) fn compile(&'b mut self, name: &str, file: &Path, functions: &[(String, RustFunction)]) -> Result> { - for section in 0..self.sections.len() { self.init_section(section); let section = &self.sections[section]; @@ -1709,21 +1626,24 @@ impl<'a, 'b> Compiler<'a> { (Some((Token::Identifier(name), _)), Some((Token::ColonColon, _)), Some((Token::Fn, _))) => { - self.forward_constant(name.to_string()); + let name = name.to_string(); + self.forward_constant(name); }, (Some((Token::Blob, _)), Some((Token::Identifier(name), _)), ..) => { - self.forward_constant(name.to_string()); + let name = name.to_string(); + self.forward_constant(name); }, (Some((Token::Identifier(name), _)), Some((Token::Colon, _)), ..) => { + let name = name.to_string(); self.eat(); self.eat(); if let Ok(ty) = self.parse_type() { let is_mut = self.peek() == Token::Equal; - let var = Variable::new(name, is_mut, ty); + let var = Variable::new(&name, is_mut, ty); let _ = self.define(var); } else { error!(self, format!("Failed to parse type global '{}'.", name)); diff --git a/src/lib.rs b/src/lib.rs index 8a023b6..5542d17 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,7 +9,6 @@ use std::hash::{Hash, Hasher}; use owo_colors::OwoColorize; use error::Error; -use tokenizer::TokenStream; use crate::error::ErrorKind; @@ -17,45 +16,39 @@ pub mod error; pub mod vm; mod compiler; +mod sectionizer; mod tokenizer; /// Compiles a file and links the supplied functions as callable external /// functions. Use this if you want your programs to be able to yield. -pub fn compile_file( - path: &Path, - print: bool, - functions: Vec<(String, RustFunction)> -) -> Result> { - let tokens = tokenizer::file_to_tokens(path); - match compiler::Compiler::new(path, &tokens).compile("main", path, &functions) { - Ok(prog) => { - let mut vm = vm::VM::new(); - vm.print_blocks = print; - vm.print_ops = print; - vm.typecheck(&prog)?; - vm.init(&prog); - Ok(vm) - } - Err(errors) => Err(errors), - } -} +//pub fn compile_file( +// path: &Path, +// print: bool, +// functions: Vec<(String, RustFunction)> +//) -> Result> { +// match compiler::Compiler::new(path).compile("main", path, &functions) { +// Ok(prog) => { +// let mut vm = vm::VM::new(); +// vm.print_blocks = print; +// vm.print_ops = print; +// vm.typecheck(&prog)?; +// vm.init(&prog); +// Ok(vm) +// } +// Err(errors) => Err(errors), +// } +//} /// Compiles, links and runs the given file. Supplied functions are callable /// external functions. If you want your program to be able to yield, use /// [compile_file]. pub fn run_file(path: &Path, print: bool, functions: Vec<(String, RustFunction)>) -> Result<(), Vec> { - run(tokenizer::file_to_tokens(path), path, print, functions) -} - -/// Compile and run a string containing source code. The supplied functions are -/// linked as callable external functions. This is useful for short test -/// programs. -pub fn run_string(s: &str, print: bool, functions: Vec<(String, RustFunction)>) -> Result<(), Vec> { - run(tokenizer::string_to_tokens(s), Path::new("builtin"), print, functions) + run(path, print, functions) } -fn run(tokens: TokenStream, path: &Path, print: bool, functions: Vec<(String, RustFunction)>) -> Result<(), Vec> { - match compiler::Compiler::new(path, &tokens).compile("main", path, &functions) { +fn run(path: &Path, print: bool, functions: Vec<(String, RustFunction)>) -> Result<(), Vec> { + let sections = sectionizer::sectionize(path); + match compiler::Compiler::new(sections).compile("main", path, &functions) { Ok(prog) => { let mut vm = vm::VM::new(); vm.print_blocks = print; diff --git a/src/sectionizer.rs b/src/sectionizer.rs new file mode 100644 index 0000000..b7e083f --- /dev/null +++ b/src/sectionizer.rs @@ -0,0 +1,109 @@ +use crate::tokenizer::{PlacedToken, Token, file_to_tokens}; + +use std::collections::HashSet; +use std::path::{Path, PathBuf}; + +pub struct Section { + pub tokens: Vec, + pub path: PathBuf, +} + +impl Section { + fn new(path: PathBuf, tokens: &[PlacedToken]) -> Self { + Self { + tokens: Vec::from(tokens), + path, + } + } +} + +pub fn sectionize(path: &Path) -> Vec
{ + let mut read_files = HashSet::new(); + read_files.insert(path.to_path_buf()); + let tokens = file_to_tokens(path); + let mut all_tokens = vec![(path.to_path_buf(), tokens)]; + let mut sections = Vec::new(); + + let mut i = 0; + while i < all_tokens.len() { + let (path, tokens) = all_tokens[i].clone(); + i += 1; + let mut last = 0; + let mut curr = 0; + while curr < tokens.len() { + if match (tokens.get(curr + 0), tokens.get(curr + 1), tokens.get(curr + 2)) { + (Some((Token::Newline, _)), ..) + => { + if curr == last { + last += 1; + } + false + }, + + (Some((Token::Use, _)), + Some((Token::Identifier(use_file), _)), + Some((Token::Newline, _))) => { + curr += 3; + let use_file: PathBuf = format!("{}.sy", use_file).into(); + if !read_files.contains(&use_file) { + let use_file_tokens = file_to_tokens(&use_file); + read_files.insert(use_file.clone()); + all_tokens.push((use_file, use_file_tokens)) + } + true + }, + + (Some((Token::LeftBrace, _)), ..) + => { + let mut blocks = 0; + loop { + curr += 1; + match tokens.get(curr) { + Some((Token::LeftBrace, _)) => { + blocks += 1; + } + + Some((Token::RightBrace, _)) => { + curr += 1; + blocks -= 1; + if blocks <= 0 { + break; + } + } + + None => { + break; + } + + _ => {} + } + } + false + }, + + (Some((Token::Identifier(_), _)), + Some((Token::ColonColon, _)), + Some((Token::Fn, _))) + => true, + + (Some((Token::Identifier(_), _)), + Some((Token::ColonColon, _)), + Some(_)) + => true, + + (Some((Token::Identifier(_), _)), + Some((Token::ColonEqual, _)), + Some(_)) + => true, + + _ => false, + } { + sections.push(Section::new(path.clone(), &tokens[last..curr])); + last = curr; + } + curr += 1; + } + sections.push(Section::new(path.clone(), &tokens[last..curr])); + } + sections +} diff --git a/src/tokenizer.rs b/src/tokenizer.rs index 2c8e5e8..3b61e5f 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -127,6 +127,9 @@ pub enum Token { #[token("\n")] Newline, + #[token("use")] + Use, + #[token("<<<<<<<")] GitConflictBegin, #[token(">>>>>>>")] -- cgit v1.2.1 From 89bdd138aa5e0843d57fc847cb4026220c06209e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Sun, 28 Feb 2021 17:24:01 +0100 Subject: uncomment missed function --- src/lib.rs | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 5542d17..629d39f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,23 +21,24 @@ mod tokenizer; /// Compiles a file and links the supplied functions as callable external /// functions. Use this if you want your programs to be able to yield. -//pub fn compile_file( -// path: &Path, -// print: bool, -// functions: Vec<(String, RustFunction)> -//) -> Result> { -// match compiler::Compiler::new(path).compile("main", path, &functions) { -// Ok(prog) => { -// let mut vm = vm::VM::new(); -// vm.print_blocks = print; -// vm.print_ops = print; -// vm.typecheck(&prog)?; -// vm.init(&prog); -// Ok(vm) -// } -// Err(errors) => Err(errors), -// } -//} +pub fn compile_file( + path: &Path, + print: bool, + functions: Vec<(String, RustFunction)> +) -> Result> { + let sections = sectionizer::sectionize(path); + match compiler::Compiler::new(sections).compile("main", path, &functions) { + Ok(prog) => { + let mut vm = vm::VM::new(); + vm.print_blocks = print; + vm.print_ops = print; + vm.typecheck(&prog)?; + vm.init(&prog); + Ok(vm) + } + Err(errors) => Err(errors), + } +} /// Compiles, links and runs the given file. Supplied functions are callable /// external functions. If you want your program to be able to yield, use -- cgit v1.2.1 From 6b4b3d9d01057c27909bab7675c2ad3ec5e910a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Sun, 28 Feb 2021 17:37:24 +0100 Subject: run strings from temporary files --- Cargo.lock | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + src/lib.rs | 7 +++++++ 3 files changed, 72 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index f7d2ec1..66a4cc8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -201,6 +201,17 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "getrandom" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "half" version = "1.7.1" @@ -367,6 +378,12 @@ dependencies = [ "plotters-backend", ] +[[package]] +name = "ppv-lite86" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" + [[package]] name = "proc-macro2" version = "1.0.24" @@ -385,6 +402,46 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" +dependencies = [ + "rand_core", +] + [[package]] name = "rayon" version = "1.5.0" @@ -524,6 +581,7 @@ dependencies = [ "criterion", "logos", "owo-colors", + "rand", "sylt_macro", ] @@ -594,6 +652,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + [[package]] name = "wasm-bindgen" version = "0.2.70" diff --git a/Cargo.toml b/Cargo.toml index f6b763f..b14b588 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ name = "sylt" [dependencies] logos = "0.11.4" owo-colors = { git="https://github.com/FredTheDino/owo-colors.git" } +rand = "0.8" sylt_macro = { path = "sylt_macro" } criterion = { version = "0.3", optional = true } diff --git a/src/lib.rs b/src/lib.rs index 629d39f..76486dd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -47,6 +47,13 @@ pub fn run_file(path: &Path, print: bool, functions: Vec<(String, RustFunction)> run(path, print, functions) } +pub fn run_string(source: &str, print: bool, functions: Vec<(String, RustFunction)>) -> Result<(), Vec> { + let mut path = std::env::temp_dir(); + path.push(format!("test_{}.sy", rand::random::())); + std::fs::write(path.clone(), source).expect("Failed to write source to temporary file"); + run(&path, print, functions) +} + fn run(path: &Path, print: bool, functions: Vec<(String, RustFunction)>) -> Result<(), Vec> { let sections = sectionizer::sectionize(path); match compiler::Compiler::new(sections).compile("main", path, &functions) { -- cgit v1.2.1 From e2eefa106a8f8b1677ba6275f5ea5879cac20974 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Sun, 28 Feb 2021 18:35:09 +0100 Subject: more wip namespaces --- src/compiler.rs | 92 +++++++++++++++++++++++++++++++++++++++--------------- src/sectionizer.rs | 1 - 2 files changed, 66 insertions(+), 27 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index 90bc51e..1d0f17b 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -315,14 +315,14 @@ impl Frame { } } -type Namespace<'a> = HashMap>; +type Namespace = HashMap; -struct CompilerContext<'a> { +struct CompilerContext { frames: Vec, - namespace: Namespace<'a>, + namespace: Namespace, } -impl<'a> CompilerContext<'a> { +impl CompilerContext { fn new() -> Self { Self { frames: vec![Frame::new()], @@ -332,18 +332,18 @@ impl<'a> CompilerContext<'a> { } #[derive(Debug)] -enum Name<'a> { +enum Name { Slot(usize, usize), Unknown(usize, usize), - _Namespace(&'a Namespace<'a>), + Namespace(PathBuf), } -pub(crate) struct Compiler<'a> { +pub(crate) struct Compiler { current_token: usize, current_section: usize, sections: Vec
, - contextes: HashMap>, + contextes: HashMap, panic: bool, errors: Vec, @@ -364,7 +364,7 @@ fn add_op(compiler: &Compiler, block: &mut Block, op: Op) -> usize { block.add(op, compiler.line()) } -impl<'a, 'b> Compiler<'a> { +impl<'a, 'b> Compiler { pub(crate) fn new(sections: Vec
) -> Self { let contextes = sections .iter() @@ -399,6 +399,18 @@ impl<'a, 'b> Compiler<'a> { id } + fn add_namespace(&mut self, name: String) { + let path = Path::new(&format!("{}.sy", name)).to_path_buf(); + match self.names_mut().entry(name.clone()) { + Entry::Vacant(v) => { + v.insert(Name::Namespace(path)); + } + Entry::Occupied(_) => { + error!(self, format!("Namespace {} already present.", name)); + } + } + } + fn add_constant(&'b mut self, value: Value) -> usize { if matches!(value, Value::Float(_) | Value::Int(_) @@ -439,7 +451,7 @@ impl<'a, 'b> Compiler<'a> { self.contextes.get(self.current_file()).unwrap() } - fn current_context_mut(&'b mut self) -> &mut CompilerContext<'a> { + fn current_context_mut(&'b mut self) -> &mut CompilerContext { let file = self.current_file().to_path_buf(); self.contextes.get_mut(&file).unwrap() } @@ -460,11 +472,11 @@ impl<'a, 'b> Compiler<'a> { &mut self.current_context_mut().frames } - fn names(&'a self) -> &Namespace<'a> { + fn names(&'a self) -> &Namespace { &self.current_context().namespace } - fn names_mut(&'b mut self) -> &mut Namespace<'a> { + fn names_mut(&'b mut self) -> &mut Namespace { &mut self.current_context_mut().namespace } @@ -757,6 +769,13 @@ impl<'a, 'b> Compiler<'a> { } } + fn find_namespace(&self, name: &str) -> Option<&Namespace> { + match self.names().get(name) { + Some(Name::Namespace(path)) => Some(&self.contextes.get(path).unwrap().namespace), + _ => None, + } + } + fn find_and_capture_variable<'i, I>(name: &str, mut iterator: I) -> Option where I: Iterator { if let Some(frame) = iterator.next() { @@ -797,7 +816,10 @@ impl<'a, 'b> Compiler<'a> { match entry.get() { Name::Slot(i, _) => { return *i; }, Name::Unknown(i, _) => { return *i; }, - _ => unreachable!(), + _ => { + error!(self, format!("Tried to find constant '{}' but it was a namespace.", name)); + return 0; + } } }, Entry::Vacant(_) => {}, @@ -922,12 +944,8 @@ impl<'a, 'b> Compiler<'a> { fn function(&'b mut self, block: &mut Block, in_name: Option<&str>) { expect!(self, Token::Fn, "Expected 'fn' at start of function."); - let top = self.stack().len() - 1; let name = if let Some(name) = in_name { String::from(name) - } else if !self.stack()[top].active { - self.stack_mut()[top].active = true; - self.stack()[top].name.clone() } else { format!("λ {}@{:03}", self.current_file().display(), self.line()) }; @@ -1406,12 +1424,28 @@ impl<'a, 'b> Compiler<'a> { self.named_constant(name, blob); } + //TODO rename fn blob_field(&'b mut self, block: &mut Block) { let name = match self.eat() { Token::Identifier(name) => name, _ => unreachable!(), }; - if let Some(var) = self.find_variable(&name) { + if let Some(_) = self.find_namespace(&name) { + expect!(self, Token::Dot, "Expected '.' after namespace."); + if let Token::Identifier(ident) = self.eat() { + match self.find_namespace(&name).unwrap().get(&ident) { + Some(Name::Slot(slot, _)) => { + add_op(self, block, Op::Constant(*slot)); + self.call_maybe(block); + } + _ => { + error!(self, "?"); + } + } + } else { + error!(self, "?"); + } + } else if let Some(var) = self.find_variable(&name) { self.mark_read(self.frames().len() - 1, &var); if var.upvalue { add_op(self, block, Op::ReadUpvalue(var.slot)); @@ -1532,7 +1566,8 @@ impl<'a, 'b> Compiler<'a> { } (Token::Identifier(_), Token::Dot, ..) => { - parse_branch!(self, block, [self.blob_field(block), self.expression(block)]); + //parse_branch!(self, block, [self.blob_field(block), self.expression(block)]); + self.blob_field(block); } (Token::Identifier(name), Token::Colon, ..) => { @@ -1615,7 +1650,6 @@ impl<'a, 'b> Compiler<'a> { add_op(self, block, Op::Pop); } } - } pub(crate) fn compile(&'b mut self, name: &str, file: &Path, functions: &[(String, RustFunction)]) -> Result> { @@ -1623,18 +1657,24 @@ impl<'a, 'b> Compiler<'a> { self.init_section(section); let section = &self.sections[section]; match (section.tokens.get(0), section.tokens.get(1), section.tokens.get(2)) { + (Some((Token::Use, _)), + Some((Token::Identifier(name), _)), ..) => { + let name = name.to_string(); + self.add_namespace(name); + } + (Some((Token::Identifier(name), _)), Some((Token::ColonColon, _)), Some((Token::Fn, _))) => { let name = name.to_string(); self.forward_constant(name); - }, + } (Some((Token::Blob, _)), Some((Token::Identifier(name), _)), ..) => { let name = name.to_string(); self.forward_constant(name); - }, + } (Some((Token::Identifier(name), _)), Some((Token::Colon, _)), ..) => { @@ -1654,19 +1694,19 @@ impl<'a, 'b> Compiler<'a> { Some((Token::ColonColon, _)), ..) => { let var = Variable::new(name, false, Type::Unknown); let _ = self.define(var); - }, + } (Some((Token::Identifier(name), _)), Some((Token::ColonEqual, _)), ..) => { let var = Variable::new(name, true, Type::Unknown); let _ = self.define(var); - }, + } (None, ..) => {} (a, b, c) => { - panic!(format!("{:?} {:?} {:?}", a, b, c)); + panic!(format!("Unknown outer token sequence: {:?} {:?} {:?}", a, b, c)); } } } @@ -1683,7 +1723,7 @@ impl<'a, 'b> Compiler<'a> { let mut block = Block::new(name, file); for section in 0..self.sections.len() { self.init_section(section); - while self.peek() != Token::EOF { + while !matches!(self.peek(), Token::EOF | Token::Use) { self.outer_statement(&mut block); expect!(self, Token::Newline | Token::EOF, "Expect newline or EOF after expression."); diff --git a/src/sectionizer.rs b/src/sectionizer.rs index b7e083f..9441663 100644 --- a/src/sectionizer.rs +++ b/src/sectionizer.rs @@ -43,7 +43,6 @@ pub fn sectionize(path: &Path) -> Vec
{ (Some((Token::Use, _)), Some((Token::Identifier(use_file), _)), Some((Token::Newline, _))) => { - curr += 3; let use_file: PathBuf = format!("{}.sy", use_file).into(); if !read_files.contains(&use_file) { let use_file_tokens = file_to_tokens(&use_file); -- cgit v1.2.1 From 7481792dacae44a7128b3ab250e28f2e6cc9b0b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Sun, 28 Feb 2021 18:37:25 +0100 Subject: add test files for importing --- main.sy | 6 ++++++ other.sy | 9 +++++++++ 2 files changed, 15 insertions(+) create mode 100644 main.sy create mode 100644 other.sy diff --git a/main.sy b/main.sy new file mode 100644 index 0000000..3730908 --- /dev/null +++ b/main.sy @@ -0,0 +1,6 @@ +use other + +start :: fn { + other.f() + print other.g() +} diff --git a/other.sy b/other.sy new file mode 100644 index 0000000..d81cd6b --- /dev/null +++ b/other.sy @@ -0,0 +1,9 @@ +f :: fn { + print "f" +} + +// answer := 42 + +g :: fn { + ret 42 +} -- cgit v1.2.1 From 630bd52c8d5a7d362066d8d05c88a1e76c6c81b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Sun, 28 Feb 2021 18:48:49 +0100 Subject: imports! --- main.sy | 2 +- other.sy | 2 +- src/compiler.rs | 12 ++++++++---- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/main.sy b/main.sy index 3730908..c23003e 100644 --- a/main.sy +++ b/main.sy @@ -2,5 +2,5 @@ use other start :: fn { other.f() - print other.g() + // print other.g() } diff --git a/other.sy b/other.sy index d81cd6b..3651af5 100644 --- a/other.sy +++ b/other.sy @@ -5,5 +5,5 @@ f :: fn { // answer := 42 g :: fn { - ret 42 + // ret answer } diff --git a/src/compiler.rs b/src/compiler.rs index 1d0f17b..984a666 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -581,7 +581,8 @@ impl<'a, 'b> Compiler { /// The line of the current token. fn line(&self) -> usize { if self.section().tokens.len() == 0 { - unreachable!("An error occured without a section."); + // unreachable!("An error occured without a section."); + 666666 } else { self.section().tokens[std::cmp::min(self.current_token, self.section().tokens.len() - 1)].1 } @@ -1433,17 +1434,19 @@ impl<'a, 'b> Compiler { if let Some(_) = self.find_namespace(&name) { expect!(self, Token::Dot, "Expected '.' after namespace."); if let Token::Identifier(ident) = self.eat() { + println!("{:#?}", self.find_namespace(&name)); match self.find_namespace(&name).unwrap().get(&ident) { - Some(Name::Slot(slot, _)) => { + Some(Name::Slot(slot, _)) | + Some(Name::Unknown(slot, _)) => { add_op(self, block, Op::Constant(*slot)); self.call_maybe(block); } _ => { - error!(self, "?"); + error!(self, format!("Cannot find constant '{}' in namespace '{}'.", ident, name)); } } } else { - error!(self, "?"); + error!(self, "Expected identifier after namespace."); } } else if let Some(var) = self.find_variable(&name) { self.mark_read(self.frames().len() - 1, &var); @@ -1745,6 +1748,7 @@ impl<'a, 'b> Compiler { } } + self.init_section(0); let constant = self.find_constant("start"); add_op(self, &mut block, Op::Constant(constant)); add_op(self, &mut block, Op::Call(0)); -- cgit v1.2.1 From 2090888dce496f893638268b0aef981c96b68ac3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Sun, 28 Feb 2021 19:10:27 +0100 Subject: imports almost work --- main.sy | 5 ++++- other.sy | 6 +++--- src/compiler.rs | 33 ++++++++++++++------------------- src/sectionizer.rs | 5 ----- 4 files changed, 21 insertions(+), 28 deletions(-) diff --git a/main.sy b/main.sy index c23003e..869323a 100644 --- a/main.sy +++ b/main.sy @@ -2,5 +2,8 @@ use other start :: fn { other.f() - // print other.g() + print other.g() + 42 <=> other.g() + other.g() <=> 42 + other.q = 1 } diff --git a/other.sy b/other.sy index 3651af5..f959b3f 100644 --- a/other.sy +++ b/other.sy @@ -2,8 +2,8 @@ f :: fn { print "f" } -// answer := 42 -g :: fn { - // ret answer +g :: fn -> int { + answer :: 42 + ret answer } diff --git a/src/compiler.rs b/src/compiler.rs index 984a666..339bd0f 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -1040,11 +1040,18 @@ impl<'a, 'b> Compiler { } fn variable_expression(&'b mut self, block: &mut Block) { - let name = match self.eat() { + let name = match self.peek() { Token::Identifier(name) => name, _ => unreachable!(), }; + if let Some(_) = self.find_namespace(&name) { + self.blob_field(block); + return; + } + + self.eat(); + // Global functions take precedence if let Some(slot) = self.find_extern_function(&name) { let string = self.add_constant(Value::ExternFunction(slot)); @@ -1432,22 +1439,8 @@ impl<'a, 'b> Compiler { _ => unreachable!(), }; if let Some(_) = self.find_namespace(&name) { - expect!(self, Token::Dot, "Expected '.' after namespace."); - if let Token::Identifier(ident) = self.eat() { - println!("{:#?}", self.find_namespace(&name)); - match self.find_namespace(&name).unwrap().get(&ident) { - Some(Name::Slot(slot, _)) | - Some(Name::Unknown(slot, _)) => { - add_op(self, block, Op::Constant(*slot)); - self.call_maybe(block); - } - _ => { - error!(self, format!("Cannot find constant '{}' in namespace '{}'.", ident, name)); - } - } - } else { - error!(self, "Expected identifier after namespace."); - } + error!(self, "Cannot treat namespace as blob."); + return; } else if let Some(var) = self.find_variable(&name) { self.mark_read(self.frames().len() - 1, &var); if var.upvalue { @@ -1569,8 +1562,9 @@ impl<'a, 'b> Compiler { } (Token::Identifier(_), Token::Dot, ..) => { - //parse_branch!(self, block, [self.blob_field(block), self.expression(block)]); - self.blob_field(block); + if !parse_branch!(self, block, self.blob_field(block)) { + self.expression(block); + } } (Token::Identifier(name), Token::Colon, ..) => { @@ -1659,6 +1653,7 @@ impl<'a, 'b> Compiler { for section in 0..self.sections.len() { self.init_section(section); let section = &self.sections[section]; + println!("SECTION: {:?} -- {:?}", section.path, section.tokens.first()); match (section.tokens.get(0), section.tokens.get(1), section.tokens.get(2)) { (Some((Token::Use, _)), Some((Token::Identifier(name), _)), ..) => { diff --git a/src/sectionizer.rs b/src/sectionizer.rs index 9441663..55f231e 100644 --- a/src/sectionizer.rs +++ b/src/sectionizer.rs @@ -80,11 +80,6 @@ pub fn sectionize(path: &Path) -> Vec
{ false }, - (Some((Token::Identifier(_), _)), - Some((Token::ColonColon, _)), - Some((Token::Fn, _))) - => true, - (Some((Token::Identifier(_), _)), Some((Token::ColonColon, _)), Some(_)) -- cgit v1.2.1 From cbab2489a182cbbbdec61b9cf6e87e2a32e7da22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Sun, 28 Feb 2021 19:11:12 +0100 Subject: clearer todo --- src/compiler.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/compiler.rs b/src/compiler.rs index 339bd0f..bec942b 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -1562,6 +1562,7 @@ impl<'a, 'b> Compiler { } (Token::Identifier(_), Token::Dot, ..) => { + // TODO(ed): This doesn't work!!!!!! if !parse_branch!(self, block, self.blob_field(block)) { self.expression(block); } -- cgit v1.2.1 From 66875980b344ca798b14a95b3b1522f1e209d9e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Mon, 1 Mar 2021 18:19:55 +0100 Subject: parse expressions containing namespaces correctly --- main.sy | 1 - src/compiler.rs | 56 ++++++++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 46 insertions(+), 11 deletions(-) diff --git a/main.sy b/main.sy index 869323a..50e0d27 100644 --- a/main.sy +++ b/main.sy @@ -5,5 +5,4 @@ start :: fn { print other.g() 42 <=> other.g() other.g() <=> 42 - other.q = 1 } diff --git a/src/compiler.rs b/src/compiler.rs index bec942b..1aee642 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -1046,8 +1046,34 @@ impl<'a, 'b> Compiler { }; if let Some(_) = self.find_namespace(&name) { - self.blob_field(block); - return; + self.eat(); + loop { + match self.peek() { + Token::Dot => { + self.eat(); + if let Token::Identifier(field) = self.eat() { + match self.find_namespace(&name).unwrap().get(&field) { + Some(Name::Slot(slot, _)) + | Some(Name::Unknown(slot, _)) => { + add_op(self, block, Op::Constant(*slot)); + self.call_maybe(block); + return; + } + _ => { + error!(self, "Invalid namespace field."); + } + } + } else { + error!(self, "Expected fieldname after '.'."); + return; + } + } + _ => { + error!(self, "Expect '.' after namespace."); + return; + } + } + } } self.eat(); @@ -1432,16 +1458,29 @@ impl<'a, 'b> Compiler { self.named_constant(name, blob); } + fn access_dotted(&mut self, block: &mut Block) { + let name = match self.peek() { + Token::Identifier(name) => name, + _ => unreachable!(), + }; + println!("dotted {}", name); + if let Some(_) = self.find_namespace(&name) { + println!("A"); + self.expression(block); + } else { + println!("B"); + parse_branch!(self, block, [self.blob_field(block), self.expression(block)]); + } + } + //TODO rename fn blob_field(&'b mut self, block: &mut Block) { let name = match self.eat() { Token::Identifier(name) => name, _ => unreachable!(), }; - if let Some(_) = self.find_namespace(&name) { - error!(self, "Cannot treat namespace as blob."); - return; - } else if let Some(var) = self.find_variable(&name) { + + if let Some(var) = self.find_variable(&name) { self.mark_read(self.frames().len() - 1, &var); if var.upvalue { add_op(self, block, Op::ReadUpvalue(var.slot)); @@ -1562,10 +1601,7 @@ impl<'a, 'b> Compiler { } (Token::Identifier(_), Token::Dot, ..) => { - // TODO(ed): This doesn't work!!!!!! - if !parse_branch!(self, block, self.blob_field(block)) { - self.expression(block); - } + self.access_dotted(block); } (Token::Identifier(name), Token::Colon, ..) => { -- cgit v1.2.1 From 504d28930448985f914d3082db9f11d4fa2d8b5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Mon, 1 Mar 2021 18:25:01 +0100 Subject: add test for namespaces in namespaces --- main.sy | 4 ++++ other.sy | 2 ++ third.sy | 3 +++ 3 files changed, 9 insertions(+) create mode 100644 third.sy diff --git a/main.sy b/main.sy index 50e0d27..e7c344d 100644 --- a/main.sy +++ b/main.sy @@ -1,8 +1,12 @@ use other +use third start :: fn { other.f() print other.g() 42 <=> other.g() other.g() <=> 42 + + other.third.print_the_third() + third.print_the_third() } diff --git a/other.sy b/other.sy index f959b3f..cee7fde 100644 --- a/other.sy +++ b/other.sy @@ -1,3 +1,5 @@ +use third + f :: fn { print "f" } diff --git a/third.sy b/third.sy new file mode 100644 index 0000000..0477077 --- /dev/null +++ b/third.sy @@ -0,0 +1,3 @@ +print_the_third :: fn { + print "three" +} -- cgit v1.2.1 From ee514d4ca694cd6cf93307572ff2e65e1266a4b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Mon, 1 Mar 2021 18:27:47 +0100 Subject: clean it up a bit --- main.sy | 2 +- src/compiler.rs | 37 +++++++++++++++---------------------- 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/main.sy b/main.sy index e7c344d..96e055d 100644 --- a/main.sy +++ b/main.sy @@ -7,6 +7,6 @@ start :: fn { 42 <=> other.g() other.g() <=> 42 - other.third.print_the_third() + // other.third.print_the_third() third.print_the_third() } diff --git a/src/compiler.rs b/src/compiler.rs index 1aee642..acb29ab 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -1048,31 +1048,24 @@ impl<'a, 'b> Compiler { if let Some(_) = self.find_namespace(&name) { self.eat(); loop { - match self.peek() { - Token::Dot => { - self.eat(); - if let Token::Identifier(field) = self.eat() { - match self.find_namespace(&name).unwrap().get(&field) { - Some(Name::Slot(slot, _)) - | Some(Name::Unknown(slot, _)) => { - add_op(self, block, Op::Constant(*slot)); - self.call_maybe(block); - return; - } - _ => { - error!(self, "Invalid namespace field."); - } - } - } else { - error!(self, "Expected fieldname after '.'."); - return; + if self.eat() != Token::Dot { + error!(self, "Expect '.' after namespace."); + return; + } + if let Token::Identifier(field) = self.eat() { + match self.find_namespace(&name).unwrap().get(&field) { + Some(Name::Slot(slot, _)) | Some(Name::Unknown(slot, _)) => { + add_op(self, block, Op::Constant(*slot)); + self.call_maybe(block); + } + _ => { + error!(self, "Invalid namespace field."); } } - _ => { - error!(self, "Expect '.' after namespace."); - return; - } + } else { + error!(self, "Expected fieldname after '.'."); } + return; } } -- cgit v1.2.1 From aa67c8b497c6f900147fdc2507a6279a18800e5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Mon, 1 Mar 2021 18:38:59 +0100 Subject: ship it!!!! --- main.sy | 2 +- src/compiler.rs | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/main.sy b/main.sy index 96e055d..e7c344d 100644 --- a/main.sy +++ b/main.sy @@ -7,6 +7,6 @@ start :: fn { 42 <=> other.g() other.g() <=> 42 - // other.third.print_the_third() + other.third.print_the_third() third.print_the_third() } diff --git a/src/compiler.rs b/src/compiler.rs index acb29ab..5d8b2bd 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -770,6 +770,10 @@ impl<'a, 'b> Compiler { } } + fn to_namespace(&self, path: &PathBuf) -> String { + path.to_str().unwrap().strip_suffix(".sy").unwrap().to_string() + } + fn find_namespace(&self, name: &str) -> Option<&Namespace> { match self.names().get(name) { Some(Name::Namespace(path)) => Some(&self.contextes.get(path).unwrap().namespace), @@ -1047,6 +1051,7 @@ impl<'a, 'b> Compiler { if let Some(_) = self.find_namespace(&name) { self.eat(); + let mut name = name; loop { if self.eat() != Token::Dot { error!(self, "Expect '.' after namespace."); @@ -1057,6 +1062,10 @@ impl<'a, 'b> Compiler { Some(Name::Slot(slot, _)) | Some(Name::Unknown(slot, _)) => { add_op(self, block, Op::Constant(*slot)); self.call_maybe(block); + return; + } + Some(Name::Namespace(inner_name)) => { + name = self.to_namespace(&inner_name); } _ => { error!(self, "Invalid namespace field."); @@ -1065,7 +1074,6 @@ impl<'a, 'b> Compiler { } else { error!(self, "Expected fieldname after '.'."); } - return; } } -- cgit v1.2.1 From 6a362119925cbcf7d14c7fa2a0d41c0745e86d92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Mon, 1 Mar 2021 18:50:29 +0100 Subject: fixed everything with a clone! --- main.sy | 1 + src/compiler.rs | 12 ++++++++---- third.sy | 2 ++ 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/main.sy b/main.sy index e7c344d..2e21a69 100644 --- a/main.sy +++ b/main.sy @@ -9,4 +9,5 @@ start :: fn { other.third.print_the_third() third.print_the_third() + third.main.other.third.main.third.print_the_third() } diff --git a/src/compiler.rs b/src/compiler.rs index 5d8b2bd..df88c7d 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -331,7 +331,7 @@ impl CompilerContext { } } -#[derive(Debug)] +#[derive(Debug, Clone)] enum Name { Slot(usize, usize), Unknown(usize, usize), @@ -1051,21 +1051,25 @@ impl<'a, 'b> Compiler { if let Some(_) = self.find_namespace(&name) { self.eat(); - let mut name = name; + // TODO(ed): This is a clone I would love to get rid of... + let mut namespace = self.find_namespace(&name).unwrap().clone(); loop { if self.eat() != Token::Dot { error!(self, "Expect '.' after namespace."); return; } if let Token::Identifier(field) = self.eat() { - match self.find_namespace(&name).unwrap().get(&field) { + match namespace.get(&field) { Some(Name::Slot(slot, _)) | Some(Name::Unknown(slot, _)) => { add_op(self, block, Op::Constant(*slot)); self.call_maybe(block); return; } Some(Name::Namespace(inner_name)) => { - name = self.to_namespace(&inner_name); + namespace = self.contextes + .get(inner_name) + .unwrap().namespace + .clone(); } _ => { error!(self, "Invalid namespace field."); diff --git a/third.sy b/third.sy index 0477077..777dd6d 100644 --- a/third.sy +++ b/third.sy @@ -1,3 +1,5 @@ +use main + print_the_third :: fn { print "three" } -- cgit v1.2.1 From 1254dc1cf955d3c310a24e3330a92cc318931654 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Mon, 1 Mar 2021 19:00:58 +0100 Subject: remove prints --- src/compiler.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index df88c7d..5ae5bdb 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -770,10 +770,6 @@ impl<'a, 'b> Compiler { } } - fn to_namespace(&self, path: &PathBuf) -> String { - path.to_str().unwrap().strip_suffix(".sy").unwrap().to_string() - } - fn find_namespace(&self, name: &str) -> Option<&Namespace> { match self.names().get(name) { Some(Name::Namespace(path)) => Some(&self.contextes.get(path).unwrap().namespace), @@ -1030,7 +1026,6 @@ impl<'a, 'b> Compiler { function_block.ty = Type::Function(args, Box::new(return_type)); let function_block = Rc::new(RefCell::new(function_block)); - // Note(ed): We deliberately add the constant as late as possible. // This behaviour is used in `constant_statement`. let function = Value::Function(Vec::new(), Rc::clone(&function_block)); @@ -1468,12 +1463,9 @@ impl<'a, 'b> Compiler { Token::Identifier(name) => name, _ => unreachable!(), }; - println!("dotted {}", name); if let Some(_) = self.find_namespace(&name) { - println!("A"); self.expression(block); } else { - println!("B"); parse_branch!(self, block, [self.blob_field(block), self.expression(block)]); } } @@ -1695,7 +1687,6 @@ impl<'a, 'b> Compiler { for section in 0..self.sections.len() { self.init_section(section); let section = &self.sections[section]; - println!("SECTION: {:?} -- {:?}", section.path, section.tokens.first()); match (section.tokens.get(0), section.tokens.get(1), section.tokens.get(2)) { (Some((Token::Use, _)), Some((Token::Identifier(name), _)), ..) => { -- cgit v1.2.1 From 9415c7db1cd00b530f82f673efc32a459a4ae789 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Mon, 1 Mar 2021 19:29:11 +0100 Subject: bugfix sectionizer --- src/compiler.rs | 1 - src/sectionizer.rs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index 5ae5bdb..295f5cf 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -1794,7 +1794,6 @@ impl<'a, 'b> Compiler { self.panic = false; } - block.debug_print(); self.blocks.insert(0, Rc::new(RefCell::new(block))); if self.errors.is_empty() { diff --git a/src/sectionizer.rs b/src/sectionizer.rs index 55f231e..c9cfcd5 100644 --- a/src/sectionizer.rs +++ b/src/sectionizer.rs @@ -54,7 +54,7 @@ pub fn sectionize(path: &Path) -> Vec
{ (Some((Token::LeftBrace, _)), ..) => { - let mut blocks = 0; + let mut blocks = 1; loop { curr += 1; match tokens.get(curr) { -- cgit v1.2.1 From d90db967bcc46ef4ae3d8d25755655da5b578073 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Mon, 1 Mar 2021 19:57:59 +0100 Subject: reading all scripts into a variable --- build.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 build.rs diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..92b63ab --- /dev/null +++ b/build.rs @@ -0,0 +1,28 @@ +use std::path::{Path, PathBuf}; + +fn find_tests(directory: &Path) -> Vec { + let mut tests = Vec::new(); + + for entry in std::fs::read_dir(directory).unwrap() { + let path = entry.unwrap().path(); + + if path.file_name().unwrap().to_str().unwrap().starts_with("_") { + continue; + } + + if path.is_dir() { + tests.append(&mut find_tests(&path)); + } else { + assert!(!path.to_str().unwrap().contains(","), "You should be ashamed."); + tests.push(path); + } + } + + tests +} + +fn main() { + let tests = find_tests(Path::new("progs/")); + let files = tests.iter().fold(String::new(), |a, b| format!("{},{}", a, b.display())); + println!("cargo:rustc-env=SCRIPTS={}", &files[1..]); +} -- cgit v1.2.1 From 9a0967033eb63d5b974fa286468c0883c3314205 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Mon, 1 Mar 2021 20:19:18 +0100 Subject: remove those unnessecary lifetimes --- src/compiler.rs | 98 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index 295f5cf..69ce39a 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -364,7 +364,7 @@ fn add_op(compiler: &Compiler, block: &mut Block, op: Op) -> usize { block.add(op, compiler.line()) } -impl<'a, 'b> Compiler { +impl Compiler { pub(crate) fn new(sections: Vec
) -> Self { let contextes = sections .iter() @@ -393,7 +393,7 @@ impl<'a, 'b> Compiler { } } - fn new_blob_id(&'b mut self) -> usize { + fn new_blob_id(&mut self) -> usize { let id = self.blob_id; self.blob_id += 1; id @@ -411,7 +411,7 @@ impl<'a, 'b> Compiler { } } - fn add_constant(&'b mut self, value: Value) -> usize { + fn add_constant(&mut self, value: Value) -> usize { if matches!(value, Value::Float(_) | Value::Int(_) | Value::Bool(_) @@ -434,7 +434,7 @@ impl<'a, 'b> Compiler { } } - fn intern_string(&'b mut self, string: String) -> usize { + fn intern_string(&mut self, string: String) -> usize { self.strings.push(string); self.strings.len() - 1 } @@ -447,11 +447,11 @@ impl<'a, 'b> Compiler { &self.section().path } - fn current_context(&'b self) -> &CompilerContext { + fn current_context(&self) -> &CompilerContext { self.contextes.get(self.current_file()).unwrap() } - fn current_context_mut(&'b mut self) -> &mut CompilerContext { + fn current_context_mut(&mut self) -> &mut CompilerContext { let file = self.current_file().to_path_buf(); self.contextes.get_mut(&file).unwrap() } @@ -460,7 +460,7 @@ impl<'a, 'b> Compiler { self.current_context().frames.last().unwrap() } - fn frame_mut(&'b mut self) -> &mut Frame { + fn frame_mut(&mut self) -> &mut Frame { self.current_context_mut().frames.last_mut().unwrap() } @@ -468,20 +468,20 @@ impl<'a, 'b> Compiler { &self.current_context().frames } - fn frames_mut(&'b mut self) -> &mut Vec { + fn frames_mut(&mut self) -> &mut Vec { &mut self.current_context_mut().frames } - fn names(&'a self) -> &Namespace { + fn names(&self) -> &Namespace { &self.current_context().namespace } - fn names_mut(&'b mut self) -> &mut Namespace { + fn names_mut(&mut self) -> &mut Namespace { &mut self.current_context_mut().namespace } /// Marks a variable as read. Also marks upvalues. - fn mark_read(&'b mut self, frame_id: usize, var: &Variable) { + fn mark_read(&mut self, frame_id: usize, var: &Variable) { // Early out if var.read { return; @@ -504,12 +504,12 @@ impl<'a, 'b> Compiler { &self.frame().stack.as_ref() } - fn stack_mut(&'b mut self) -> &mut Vec { + fn stack_mut(&mut self) -> &mut Vec { &mut self.frame_mut().stack } /// Used to recover from a panic so the rest of the code can be parsed. - fn clear_panic(&'b mut self) { + fn clear_panic(&mut self) { if self.panic { self.panic = false; @@ -523,11 +523,11 @@ impl<'a, 'b> Compiler { } } - fn error(&'b mut self, kind: ErrorKind, message: Option) { + fn error(&mut self, kind: ErrorKind, message: Option) { self.error_on_line(kind, self.line(), message); } - fn error_on_line(&'b mut self, kind: ErrorKind, line: usize, message: Option) { + fn error_on_line(&mut self, kind: ErrorKind, line: usize, message: Option) { if self.panic { return } self.panic = true; self.errors.push(Error { @@ -538,7 +538,7 @@ impl<'a, 'b> Compiler { }); } - fn init_section(&'b mut self, section: usize) { + fn init_section(&mut self, section: usize) { self.current_token = 0; self.current_section = section; } @@ -560,7 +560,7 @@ impl<'a, 'b> Compiler { (self.peek_at(0), self.peek_at(1), self.peek_at(2), self.peek_at(3)) } - fn eat(&'b mut self) -> Token { + fn eat(&mut self) -> Token { let t = self.peek(); self.current_token += 1; match t { @@ -610,7 +610,7 @@ impl<'a, 'b> Compiler { } } - fn prefix(&'b mut self, token: Token, block: &mut Block) -> bool { + fn prefix(&mut self, token: Token, block: &mut Block) -> bool { match token { Token::Identifier(_) => self.variable_expression(block), Token::LeftParen => self.grouping_or_tuple(block), @@ -628,7 +628,7 @@ impl<'a, 'b> Compiler { return true; } - fn infix(&'b mut self, token: Token, block: &mut Block) -> bool { + fn infix(&mut self, token: Token, block: &mut Block) -> bool { match token { Token::Minus | Token::Plus @@ -650,7 +650,7 @@ impl<'a, 'b> Compiler { return true; } - fn value(&'b mut self, block: &mut Block) { + fn value(&mut self, block: &mut Block) { let value = match self.eat() { Token::Float(f) => { Value::Float(f) }, Token::Int(i) => { Value::Int(i) } @@ -662,11 +662,11 @@ impl<'a, 'b> Compiler { add_op(self, block, Op::Constant(constant)); } - fn grouping_or_tuple(&'b mut self, block: &mut Block) { + fn grouping_or_tuple(&mut self, block: &mut Block) { parse_branch!(self, block, [self.tuple(block), self.grouping(block)]); } - fn tuple(&'b mut self, block: &mut Block) { + fn tuple(&mut self, block: &mut Block) { expect!(self, Token::LeftParen, "Expected '(' at start of tuple"); let mut num_args = 0; @@ -701,7 +701,7 @@ impl<'a, 'b> Compiler { add_op(self, block, Op::Tuple(num_args)); } - fn grouping(&'b mut self, block: &mut Block) { + fn grouping(&mut self, block: &mut Block) { expect!(self, Token::LeftParen, "Expected '(' around expression."); self.expression(block); @@ -709,7 +709,7 @@ impl<'a, 'b> Compiler { expect!(self, Token::RightParen, "Expected ')' around expression."); } - fn index(&'b mut self, block: &mut Block) { + fn index(&mut self, block: &mut Block) { expect!(self, Token::LeftBracket, "Expected '[' around index."); self.expression(block); @@ -718,7 +718,7 @@ impl<'a, 'b> Compiler { expect!(self, Token::RightBracket, "Expected ']' around index."); } - fn unary(&'b mut self, block: &mut Block) { + fn unary(&mut self, block: &mut Block) { let op = match self.eat() { Token::Minus => Op::Neg, Token::Bang => Op::Not, @@ -728,7 +728,7 @@ impl<'a, 'b> Compiler { add_op(self, block, op); } - fn binary(&'b mut self, block: &mut Block) { + fn binary(&mut self, block: &mut Block) { let op = self.eat(); self.parse_precedence(block, self.precedence(op.clone()).next()); @@ -751,14 +751,14 @@ impl<'a, 'b> Compiler { } /// Entry point for all expression parsing. - fn expression(&'b mut self, block: &mut Block) { + fn expression(&mut self, block: &mut Block) { match self.peek_four() { (Token::Fn, ..) => { self.function(block, None); }, _ => self.parse_precedence(block, Prec::No), } } - fn parse_precedence(&'b mut self, block: &mut Block, precedence: Prec) { + fn parse_precedence(&mut self, block: &mut Block, precedence: Prec) { if !self.prefix(self.peek(), block) { error!(self, "Invalid expression."); } @@ -799,7 +799,7 @@ impl<'a, 'b> Compiler { self.functions.get(name).map(|(i, _)| *i) } - fn find_variable(&'b mut self, name: &str) -> Option { + fn find_variable(&mut self, name: &str) -> Option { if let Some(res) = self.frame().find_local(name) { return Some(res); } @@ -811,7 +811,7 @@ impl<'a, 'b> Compiler { Self::find_and_capture_variable(name, self.frames_mut().iter_mut().rev()) } - fn find_constant(&'b mut self, name: &str) -> usize { + fn find_constant(&mut self, name: &str) -> usize { match self.names_mut().entry(name.to_string()) { Entry::Occupied(entry) => { match entry.get() { @@ -832,7 +832,7 @@ impl<'a, 'b> Compiler { slot } - fn named_constant(&'b mut self, name: String, value: Value) -> usize { + fn named_constant(&mut self, name: String, value: Value) -> usize { let line = self.line(); match self.names_mut().entry(name.clone()) { Entry::Occupied(mut entry) => { @@ -853,7 +853,7 @@ impl<'a, 'b> Compiler { slot } - fn forward_constant(&'b mut self, name: String) -> usize { + fn forward_constant(&mut self, name: String) -> usize { let line = self.line(); let slot = self.add_constant(Value::Unknown); match self.names_mut().entry(name.clone()) { @@ -868,7 +868,7 @@ impl<'a, 'b> Compiler { } } - fn call_maybe(&'b mut self, block: &mut Block) -> bool { + fn call_maybe(&mut self, block: &mut Block) -> bool { if matches!(self.peek(), Token::Bang | Token::LeftParen) { self.call(block); true @@ -877,7 +877,7 @@ impl<'a, 'b> Compiler { } } - fn call(&'b mut self, block: &mut Block) { + fn call(&mut self, block: &mut Block) { let mut arity = 0; match self.peek() { Token::LeftParen => { @@ -942,7 +942,7 @@ impl<'a, 'b> Compiler { } // TODO(ed): de-complexify - fn function(&'b mut self, block: &mut Block, in_name: Option<&str>) { + fn function(&mut self, block: &mut Block, in_name: Option<&str>) { expect!(self, Token::Fn, "Expected 'fn' at start of function."); let name = if let Some(name) = in_name { @@ -1038,7 +1038,7 @@ impl<'a, 'b> Compiler { add_op(self, block, Op::Constant(constant)); } - fn variable_expression(&'b mut self, block: &mut Block) { + fn variable_expression(&mut self, block: &mut Block) { let name = match self.peek() { Token::Identifier(name) => name, _ => unreachable!(), @@ -1121,7 +1121,7 @@ impl<'a, 'b> Compiler { self.call_maybe(block); } - fn define(&'b mut self, mut var: Variable) -> Result { + fn define(&mut self, mut var: Variable) -> Result { if let Some(var) = self.find_variable(&var.name) { if var.scope == self.frame().scope { error!(self, format!("Multiple definitions of '{}' in this block.", @@ -1138,7 +1138,7 @@ impl<'a, 'b> Compiler { Ok(slot) } - fn definition_statement(&'b mut self, name: &str, typ: Type, block: &mut Block) { + fn definition_statement(&mut self, name: &str, typ: Type, block: &mut Block) { if self.frames().len() <= 1 { // Global let var = self.find_variable(name) @@ -1162,7 +1162,7 @@ impl<'a, 'b> Compiler { } } - fn constant_statement(&'b mut self, name: &str, typ: Type, block: &mut Block) { + fn constant_statement(&mut self, name: &str, typ: Type, block: &mut Block) { // Magical global constants if self.frames().len() <= 1 && self.peek() == Token::Fn { self.function(block, Some(name)); @@ -1200,7 +1200,7 @@ impl<'a, 'b> Compiler { } } - fn assign(&'b mut self, block: &mut Block) { + fn assign(&mut self, block: &mut Block) { let name = match self.eat() { Token::Identifier(name) => name, _ => { @@ -1250,7 +1250,7 @@ impl<'a, 'b> Compiler { } } - fn scope(&'b mut self, block: &mut Block) { + fn scope(&mut self, block: &mut Block) { if !expect!(self, Token::LeftBrace, "Expected '{' at start of block.") { return; } @@ -1269,7 +1269,7 @@ impl<'a, 'b> Compiler { expect!(self, Token::RightBrace, "Expected '}' at end of block."); } - fn if_statment(&'b mut self, block: &mut Block) { + fn if_statment(&mut self, block: &mut Block) { expect!(self, Token::If, "Expected 'if' at start of if-statement."); self.expression(block); let jump = add_op(self, block, Op::Illegal); @@ -1293,7 +1293,7 @@ impl<'a, 'b> Compiler { } //TODO de-complexify - fn for_loop(&'b mut self, block: &mut Block) { + fn for_loop(&mut self, block: &mut Block) { expect!(self, Token::For, "Expected 'for' at start of for-loop."); push_scope!(self, block, { @@ -1338,7 +1338,7 @@ impl<'a, 'b> Compiler { }); } - fn parse_type(&'b mut self) -> Result { + fn parse_type(&mut self) -> Result { match self.peek() { Token::Fn => { @@ -1415,7 +1415,7 @@ impl<'a, 'b> Compiler { } } - fn blob_statement(&'b mut self, _block: &mut Block) { + fn blob_statement(&mut self, _block: &mut Block) { expect!(self, Token::Blob, "Expected blob when declaring a blob"); let name = if let Token::Identifier(name) = self.eat() { name @@ -1471,7 +1471,7 @@ impl<'a, 'b> Compiler { } //TODO rename - fn blob_field(&'b mut self, block: &mut Block) { + fn blob_field(&mut self, block: &mut Block) { let name = match self.eat() { Token::Identifier(name) => name, _ => unreachable!(), @@ -1539,7 +1539,7 @@ impl<'a, 'b> Compiler { } } - fn outer_statement(&'b mut self, block: &mut Block) { + fn outer_statement(&mut self, block: &mut Block) { self.clear_panic(); match self.peek_four() { (Token::Identifier(name), Token::ColonEqual, ..) => { @@ -1577,7 +1577,7 @@ impl<'a, 'b> Compiler { } } - fn statement(&'b mut self, block: &mut Block) { + fn statement(&mut self, block: &mut Block) { self.clear_panic(); match self.peek_four() { @@ -1683,7 +1683,7 @@ impl<'a, 'b> Compiler { } } - pub(crate) fn compile(&'b mut self, name: &str, file: &Path, functions: &[(String, RustFunction)]) -> Result> { + pub(crate) fn compile(&mut self, name: &str, file: &Path, functions: &[(String, RustFunction)]) -> Result> { for section in 0..self.sections.len() { self.init_section(section); let section = &self.sections[section]; -- cgit v1.2.1 From ba2a7b3290102e3573cc7b2727026f4efe8a1d9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Fri, 5 Mar 2021 17:43:16 +0100 Subject: macro that generates tests from files --- src/lib.rs | 2 ++ sylt_macro/src/lib.rs | 46 ++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 76486dd..ee5f9c4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -918,6 +918,8 @@ mod tests { }; } + sylt_macro::find_tests!(); + #[test] fn unreachable_token() { assert_errs!(run_string("\n", true, Vec::new()), [ErrorKind::Unreachable]); diff --git a/sylt_macro/src/lib.rs b/sylt_macro/src/lib.rs index 3b8b37c..0f1a584 100644 --- a/sylt_macro/src/lib.rs +++ b/sylt_macro/src/lib.rs @@ -1,5 +1,7 @@ +use std::path::{Path, PathBuf}; + use proc_macro::TokenStream; -use quote::quote; +use quote::{format_ident, quote}; use syn::{Expr, Pat, Token, parse::{Parse, ParseStream, Result}, parse_macro_input}; struct ExternBlock { @@ -137,7 +139,6 @@ impl Parse for Links { } } - #[proc_macro] pub fn link(tokens: TokenStream) -> TokenStream { let links: Links = parse_macro_input!(tokens); @@ -159,3 +160,44 @@ pub fn link(tokens: TokenStream) -> TokenStream { }; TokenStream::from(tokens) } + +fn find_test_paths(directory: &Path) -> Vec { + let mut tests = Vec::new(); + + for entry in std::fs::read_dir(directory).unwrap() { + let path = entry.unwrap().path(); + let file_name = path.file_name().unwrap().to_str().unwrap(); + + if file_name.starts_with("_") { + continue; + } + + if path.is_dir() { + tests.append(&mut find_test_paths(&path)); + } else { + assert!(!path.to_str().unwrap().contains(","), "You should be ashamed."); + tests.push(path); + } + } + + tests +} + +#[proc_macro] +pub fn find_tests(tokens: TokenStream) -> TokenStream { + assert!(tokens.is_empty()); + + let tests: Vec<_> = find_test_paths(Path::new("progs/")).iter().map(|path| { + let path = path.to_str().unwrap(); + let test_name = format_ident!("{}", path.replace("/", "_").replace(".sy", "")); + quote! { + test_file!(#test_name, #path); + } + }).collect(); + + let tokens = quote! { + #(#tests)* + }; + + TokenStream::from(tokens) +} -- cgit v1.2.1 From e1e7337239066677dd6bc82b826e861cf6710836 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Fri, 5 Mar 2021 18:14:05 +0100 Subject: expand test-files in modules --- Cargo.lock | 1 + src/lib.rs | 8 +++----- sylt_macro/Cargo.toml | 5 +++-- sylt_macro/src/lib.rs | 38 +++++++++++++++++++------------------- 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 66a4cc8..6d4b83b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -589,6 +589,7 @@ dependencies = [ name = "sylt_macro" version = "0.1.0" dependencies = [ + "proc-macro2", "quote", "syn", ] diff --git a/src/lib.rs b/src/lib.rs index ee5f9c4..e26b3ab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -802,11 +802,9 @@ pub struct Prog { #[cfg(test)] mod tests { - use std::path::Path; - use crate::error::ErrorKind; - use super::{run_file, run_string}; + use super::run_string; #[macro_export] macro_rules! assert_errs { @@ -912,8 +910,8 @@ mod tests { ($fn:ident, $path:literal) => { #[test] fn $fn() { - let file = Path::new($path); - run_file(&file, true, Vec::new()).unwrap(); + let file = std::path::Path::new($path); + crate::run_file(&file, true, Vec::new()).unwrap(); } }; } diff --git a/sylt_macro/Cargo.toml b/sylt_macro/Cargo.toml index 9ac045e..6d3c75f 100644 --- a/sylt_macro/Cargo.toml +++ b/sylt_macro/Cargo.toml @@ -10,5 +10,6 @@ proc-macro = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -syn = { version = "1.0", features=["full"] } -quote = "1.0" +syn = { version = "1", features=["full"] } +proc-macro2 = "1" +quote = "1" diff --git a/sylt_macro/src/lib.rs b/sylt_macro/src/lib.rs index 0f1a584..c306592 100644 --- a/sylt_macro/src/lib.rs +++ b/sylt_macro/src/lib.rs @@ -1,4 +1,4 @@ -use std::path::{Path, PathBuf}; +use std::path::Path; use proc_macro::TokenStream; use quote::{format_ident, quote}; @@ -161,8 +161,8 @@ pub fn link(tokens: TokenStream) -> TokenStream { TokenStream::from(tokens) } -fn find_test_paths(directory: &Path) -> Vec { - let mut tests = Vec::new(); +fn find_test_paths(directory: &Path) -> proc_macro2::TokenStream { + let mut tests = quote! {}; for entry in std::fs::read_dir(directory).unwrap() { let path = entry.unwrap().path(); @@ -173,31 +173,31 @@ fn find_test_paths(directory: &Path) -> Vec { } if path.is_dir() { - tests.append(&mut find_test_paths(&path)); + tests.extend(find_test_paths(&path)); } else { assert!(!path.to_str().unwrap().contains(","), "You should be ashamed."); - tests.push(path); + + let path = path.to_str().unwrap(); + let test_name = format_ident!("file_{}", file_name.replace(".sy", "")); + let tokens = quote! { + test_file!(#test_name, #path); + }; + tests.extend(tokens); } } - tests + let directory = directory.file_name().unwrap().to_str().unwrap().replace("/", ""); + let directory = format_ident!("{}", directory); + quote! { + mod #directory { + #tests + } + } } #[proc_macro] pub fn find_tests(tokens: TokenStream) -> TokenStream { assert!(tokens.is_empty()); - let tests: Vec<_> = find_test_paths(Path::new("progs/")).iter().map(|path| { - let path = path.to_str().unwrap(); - let test_name = format_ident!("{}", path.replace("/", "_").replace(".sy", "")); - quote! { - test_file!(#test_name, #path); - } - }).collect(); - - let tokens = quote! { - #(#tests)* - }; - - TokenStream::from(tokens) + TokenStream::from(find_test_paths(Path::new("progs/"))) } -- cgit v1.2.1 From 9d0a930d811b825b39ee16614e645b6934130cc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Fri, 5 Mar 2021 18:37:23 +0100 Subject: parse wanted errors from test files --- progs/tests/unreachable.sy | 6 +++++- src/lib.rs | 10 ++++++++++ sylt_macro/src/lib.rs | 38 ++++++++++++++++++++++++++++---------- 3 files changed, 43 insertions(+), 11 deletions(-) diff --git a/progs/tests/unreachable.sy b/progs/tests/unreachable.sy index f016a14..5a59ae1 100644 --- a/progs/tests/unreachable.sy +++ b/progs/tests/unreachable.sy @@ -1 +1,5 @@ - +start :: fn { + +} + +// errors: [ErrorKind::Unreachable] diff --git a/src/lib.rs b/src/lib.rs index e26b3ab..03abd48 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -914,6 +914,16 @@ mod tests { crate::run_file(&file, true, Vec::new()).unwrap(); } }; + ($fn:ident, $path:literal, $errs:tt) => { + #[test] + fn $fn() { + use crate::error::ErrorKind; + + let file = std::path::Path::new($path); + let res = crate::run_file(&file, true, Vec::new()); + $crate::assert_errs!(res, $errs); + } + }; } sylt_macro::find_tests!(); diff --git a/sylt_macro/src/lib.rs b/sylt_macro/src/lib.rs index c306592..96f7112 100644 --- a/sylt_macro/src/lib.rs +++ b/sylt_macro/src/lib.rs @@ -1,6 +1,5 @@ use std::path::Path; -use proc_macro::TokenStream; use quote::{format_ident, quote}; use syn::{Expr, Pat, Token, parse::{Parse, ParseStream, Result}, parse_macro_input}; @@ -45,7 +44,7 @@ impl Parse for ExternFunction { } #[proc_macro] -pub fn extern_function(tokens: TokenStream) -> TokenStream { +pub fn extern_function(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream { let parsed: ExternFunction = parse_macro_input!(tokens); let function = parsed.function; @@ -91,7 +90,7 @@ pub fn extern_function(tokens: TokenStream) -> TokenStream { } } }; - TokenStream::from(tokens) + proc_macro::TokenStream::from(tokens) } struct LinkRename { @@ -140,7 +139,7 @@ impl Parse for Links { } #[proc_macro] -pub fn link(tokens: TokenStream) -> TokenStream { +pub fn link(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream { let links: Links = parse_macro_input!(tokens); let links: Vec<_> = links.links.iter().map(|link| { @@ -158,7 +157,16 @@ pub fn link(tokens: TokenStream) -> TokenStream { let tokens = quote! { vec![ #(#links),* ] }; - TokenStream::from(tokens) + proc_macro::TokenStream::from(tokens) +} + +fn parse_test(contents: String) -> Option { + for line in contents.split("\n") { + if line.starts_with("// errors: ") { + return Some(line.strip_prefix("// errors: ").unwrap().to_string()); + } + } + None } fn find_test_paths(directory: &Path) -> proc_macro2::TokenStream { @@ -177,11 +185,20 @@ fn find_test_paths(directory: &Path) -> proc_macro2::TokenStream { } else { assert!(!path.to_str().unwrap().contains(","), "You should be ashamed."); - let path = path.to_str().unwrap(); + let path_string = path.to_str().unwrap(); let test_name = format_ident!("file_{}", file_name.replace(".sy", "")); - let tokens = quote! { - test_file!(#test_name, #path); + + let tokens = if let Some(wanted_err) = parse_test(std::fs::read_to_string(path.clone()).unwrap()) { + let wanted_err: proc_macro2::TokenStream = wanted_err.parse().unwrap(); + quote! { + test_file!(#test_name, #path_string, #wanted_err); + } + } else { + quote! { + test_file!(#test_name, #path_string); + } }; + tests.extend(tokens); } } @@ -196,8 +213,9 @@ fn find_test_paths(directory: &Path) -> proc_macro2::TokenStream { } #[proc_macro] -pub fn find_tests(tokens: TokenStream) -> TokenStream { +pub fn find_tests(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream { assert!(tokens.is_empty()); - TokenStream::from(find_test_paths(Path::new("progs/"))) + let tokens = find_test_paths(Path::new("progs/")); + proc_macro::TokenStream::from(tokens) } -- cgit v1.2.1 From 2570830850c6dadadc2c86bf9d6f3203c9aba488 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Fri, 5 Mar 2021 19:07:13 +0100 Subject: convert tests to files --- progs/bench/fib.sy | 6 +- progs/bench/fib_iter.sy | 21 +- progs/bench/sum.sy | 13 +- progs/tests/_simple.sy | 23 + progs/tests/auto/add.sy | 3 + progs/tests/auto/advanced_break.sy | 22 + progs/tests/auto/advanced_continue.sy | 22 + progs/tests/auto/assignment.sy | 7 + progs/tests/auto/blob_complex.sy | 19 + progs/tests/auto/blob_infer.sy | 8 + progs/tests/auto/blob_simple.sy | 10 + progs/tests/auto/calls_inside_calls.sy | 11 + progs/tests/auto/cluster.sy | 14 + progs/tests/auto/compare_constants_equality.sy | 5 + progs/tests/auto/compare_constants_unequality.sy | 5 + progs/tests/auto/compare_variable.sy | 9 + progs/tests/auto/conflict_markers.sy | 11 + progs/tests/auto/constant_function.sy | 4 + progs/tests/auto/constant_function_closure.sy | 13 + progs/tests/auto/constant_function_complex.sy | 19 + progs/tests/auto/constants_in_inner_functions.sy | 20 + progs/tests/auto/div.sy | 5 + progs/tests/auto/else_.sy | 10 + progs/tests/auto/else_if.sy | 12 + progs/tests/auto/expressions.sy | 6 + progs/tests/auto/factorial.sy | 12 + progs/tests/auto/field.sy | 3 + progs/tests/auto/field_assign.sy | 5 + progs/tests/auto/field_get.sy | 7 + progs/tests/auto/in_rhs.sy | 3 + progs/tests/auto/instantiate.sy | 5 + progs/tests/auto/invalid_assign.sy | 7 + progs/tests/auto/more_types.sy | 4 + progs/tests/auto/mul.sy | 3 + progs/tests/auto/multiple_fields.sy | 11 + progs/tests/auto/multiple_returns.sy | 12 + progs/tests/auto/negation.sy | 7 + progs/tests/auto/not.sy | 5 + progs/tests/auto/one_arg.sy | 5 + progs/tests/auto/param_1.sy | 4 + progs/tests/auto/param_2.sy | 7 + progs/tests/auto/param_and_return.sy | 7 + progs/tests/auto/parenthesis.sy | 3 + progs/tests/auto/passing_functions.sy | 9 + progs/tests/auto/passing_functions_mixed.sy | 9 + progs/tests/auto/precedence.sy | 8 + progs/tests/auto/return_1.sy | 6 + progs/tests/auto/returning_closures.sy | 24 + progs/tests/auto/simple.sy | 10 + progs/tests/auto/simple_add.sy | 9 + progs/tests/auto/simple_break.sy | 12 + progs/tests/auto/simple_continue.sy | 12 + progs/tests/auto/simple_sub.sy | 9 + progs/tests/auto/simplest.sy | 4 + progs/tests/auto/single_variable.sy | 4 + progs/tests/auto/stack_ordering.sy | 6 + progs/tests/auto/strange.sy | 15 + progs/tests/auto/sub.sy | 3 + progs/tests/auto/terms_and_factors.sy | 4 + progs/tests/auto/three_arg.sy | 5 + progs/tests/auto/two_arg.sy | 5 + progs/tests/auto/two_variables.sy | 6 + progs/tests/auto/types.sy | 4 + progs/tests/auto/uncallable_type.sy | 9 + progs/tests/auto/wrong_params.sy | 7 + progs/tests/auto/wrong_ret.sy | 7 + progs/tests/faulty.sy | 2 + progs/tests/fib.sy | 16 +- progs/tests/for.sy | 32 +- progs/tests/scoping.sy | 24 +- progs/tests/simple.sy | 23 - src/lib.rs | 546 +---------------------- src/vm.rs | 26 -- 73 files changed, 622 insertions(+), 642 deletions(-) create mode 100644 progs/tests/_simple.sy create mode 100644 progs/tests/auto/add.sy create mode 100644 progs/tests/auto/advanced_break.sy create mode 100644 progs/tests/auto/advanced_continue.sy create mode 100644 progs/tests/auto/assignment.sy create mode 100644 progs/tests/auto/blob_complex.sy create mode 100644 progs/tests/auto/blob_infer.sy create mode 100644 progs/tests/auto/blob_simple.sy create mode 100644 progs/tests/auto/calls_inside_calls.sy create mode 100644 progs/tests/auto/cluster.sy create mode 100644 progs/tests/auto/compare_constants_equality.sy create mode 100644 progs/tests/auto/compare_constants_unequality.sy create mode 100644 progs/tests/auto/compare_variable.sy create mode 100644 progs/tests/auto/conflict_markers.sy create mode 100644 progs/tests/auto/constant_function.sy create mode 100644 progs/tests/auto/constant_function_closure.sy create mode 100644 progs/tests/auto/constant_function_complex.sy create mode 100644 progs/tests/auto/constants_in_inner_functions.sy create mode 100644 progs/tests/auto/div.sy create mode 100644 progs/tests/auto/else_.sy create mode 100644 progs/tests/auto/else_if.sy create mode 100644 progs/tests/auto/expressions.sy create mode 100644 progs/tests/auto/factorial.sy create mode 100644 progs/tests/auto/field.sy create mode 100644 progs/tests/auto/field_assign.sy create mode 100644 progs/tests/auto/field_get.sy create mode 100644 progs/tests/auto/in_rhs.sy create mode 100644 progs/tests/auto/instantiate.sy create mode 100644 progs/tests/auto/invalid_assign.sy create mode 100644 progs/tests/auto/more_types.sy create mode 100644 progs/tests/auto/mul.sy create mode 100644 progs/tests/auto/multiple_fields.sy create mode 100644 progs/tests/auto/multiple_returns.sy create mode 100644 progs/tests/auto/negation.sy create mode 100644 progs/tests/auto/not.sy create mode 100644 progs/tests/auto/one_arg.sy create mode 100644 progs/tests/auto/param_1.sy create mode 100644 progs/tests/auto/param_2.sy create mode 100644 progs/tests/auto/param_and_return.sy create mode 100644 progs/tests/auto/parenthesis.sy create mode 100644 progs/tests/auto/passing_functions.sy create mode 100644 progs/tests/auto/passing_functions_mixed.sy create mode 100644 progs/tests/auto/precedence.sy create mode 100644 progs/tests/auto/return_1.sy create mode 100644 progs/tests/auto/returning_closures.sy create mode 100644 progs/tests/auto/simple.sy create mode 100644 progs/tests/auto/simple_add.sy create mode 100644 progs/tests/auto/simple_break.sy create mode 100644 progs/tests/auto/simple_continue.sy create mode 100644 progs/tests/auto/simple_sub.sy create mode 100644 progs/tests/auto/simplest.sy create mode 100644 progs/tests/auto/single_variable.sy create mode 100644 progs/tests/auto/stack_ordering.sy create mode 100644 progs/tests/auto/strange.sy create mode 100644 progs/tests/auto/sub.sy create mode 100644 progs/tests/auto/terms_and_factors.sy create mode 100644 progs/tests/auto/three_arg.sy create mode 100644 progs/tests/auto/two_arg.sy create mode 100644 progs/tests/auto/two_variables.sy create mode 100644 progs/tests/auto/types.sy create mode 100644 progs/tests/auto/uncallable_type.sy create mode 100644 progs/tests/auto/wrong_params.sy create mode 100644 progs/tests/auto/wrong_ret.sy delete mode 100644 progs/tests/simple.sy diff --git a/progs/bench/fib.sy b/progs/bench/fib.sy index de68f5c..76c3af7 100644 --- a/progs/bench/fib.sy +++ b/progs/bench/fib.sy @@ -7,4 +7,8 @@ fib :: fn a:int -> int { ret fib(a - 1) + fib(a - 2) } // 23 is around where things start getting slow. -fib(23) <=> 28657 +start :: fn { + //TODO pass arguments to skip debug printing. this test is very slow otherwise + + // fib(23) <=> 28657 +} diff --git a/progs/bench/fib_iter.sy b/progs/bench/fib_iter.sy index c51469a..f82d6f8 100644 --- a/progs/bench/fib_iter.sy +++ b/progs/bench/fib_iter.sy @@ -1,14 +1,17 @@ // A Fibonacci implementation that is a little // less awful. But we run it 1000 times instead. -j := 0 -for , j < 1000, j = j + 1 { - a := 0 - b := 1 +start :: fn { + + j := 0 + for , j < 1000, j = j + 1 { + a := 0 + b := 1 - for i := 0, i < 50, i = i + 1 { - c := a - a = b - b = c + b + for i := 0, i < 50, i = i + 1 { + c := a + a = b + b = c + b + } + a <=> 12586269025 } - a <=> 12586269025 } diff --git a/progs/bench/sum.sy b/progs/bench/sum.sy index bb6870f..39252cd 100644 --- a/progs/bench/sum.sy +++ b/progs/bench/sum.sy @@ -1,6 +1,9 @@ -// Adds the numbers 0 to 10000 -sum := 0 -for i := 0, i <= 100000, i += 1 { - sum += i +// Adds the numbers 0 to 100000 +start :: fn { + + sum := 0 + for i := 0, i <= 100000, i += 1 { + sum += i + } + sum <=> 5000050000 } -sum <=> 5000050000 diff --git a/progs/tests/_simple.sy b/progs/tests/_simple.sy new file mode 100644 index 0000000..84bc86d --- /dev/null +++ b/progs/tests/_simple.sy @@ -0,0 +1,23 @@ +// +// import A + +// +f :: fn { + g! + print q +} + +// +q :: 1 + +// +a := 1 + +qq :: fn { + g! + print q +} + + +// Steg 1: Hitta sektioner +// Dela sektioner, compilera felera sektioner efter varandra diff --git a/progs/tests/auto/add.sy b/progs/tests/auto/add.sy new file mode 100644 index 0000000..4e8e643 --- /dev/null +++ b/progs/tests/auto/add.sy @@ -0,0 +1,3 @@ +start :: fn { +(1, 2, 3, 4) + (4, 3, 2, 1) <=> (5, 5, 5, 5) +} diff --git a/progs/tests/auto/advanced_break.sy b/progs/tests/auto/advanced_break.sy new file mode 100644 index 0000000..1cfcece --- /dev/null +++ b/progs/tests/auto/advanced_break.sy @@ -0,0 +1,22 @@ +start :: fn { + +a := 0 +for i := 0, i < 10, i += 1 { + q := 0 + qq := 0 + qqq := 0 + qqqq := 0 + + a = a + 1 + if i == 2 { + break + } + + q + qq + qqq + qqqq +} +a <=> 3 + +} diff --git a/progs/tests/auto/advanced_continue.sy b/progs/tests/auto/advanced_continue.sy new file mode 100644 index 0000000..70a8671 --- /dev/null +++ b/progs/tests/auto/advanced_continue.sy @@ -0,0 +1,22 @@ +start :: fn { + +a := 0 +for i := 0, i < 4, i += 1 { + q := 0 + qq := 0 + qqq := 0 + qqqq := 0 + + if i == 2 { + continue + } + a = a + 1 + + q + qq + qqq + qqqq +} +a <=> 3 + +} diff --git a/progs/tests/auto/assignment.sy b/progs/tests/auto/assignment.sy new file mode 100644 index 0000000..51cbecc --- /dev/null +++ b/progs/tests/auto/assignment.sy @@ -0,0 +1,7 @@ +start :: fn { +a := 1 + b := 2 + a = b + a <=> 2 + b <=> 2 +} diff --git a/progs/tests/auto/blob_complex.sy b/progs/tests/auto/blob_complex.sy new file mode 100644 index 0000000..d40082f --- /dev/null +++ b/progs/tests/auto/blob_complex.sy @@ -0,0 +1,19 @@ +start :: fn { + +a := A() +b := B() +c := C() +b2 := B() + +a +b +c +b2 + +blob A { + c: C +} +blob C { } +blob B { } + +} diff --git a/progs/tests/auto/blob_infer.sy b/progs/tests/auto/blob_infer.sy new file mode 100644 index 0000000..cee18bf --- /dev/null +++ b/progs/tests/auto/blob_infer.sy @@ -0,0 +1,8 @@ +start :: fn { + +blob A { } + +a : A = A() +a + +} diff --git a/progs/tests/auto/blob_simple.sy b/progs/tests/auto/blob_simple.sy new file mode 100644 index 0000000..f05ec07 --- /dev/null +++ b/progs/tests/auto/blob_simple.sy @@ -0,0 +1,10 @@ +start :: fn { + +a := A() +a + +blob A { + a: int +} + +} diff --git a/progs/tests/auto/calls_inside_calls.sy b/progs/tests/auto/calls_inside_calls.sy new file mode 100644 index 0000000..578f418 --- /dev/null +++ b/progs/tests/auto/calls_inside_calls.sy @@ -0,0 +1,11 @@ +start :: fn { +one := fn -> int { + ret 1 + } + add := fn a: int, b: int -> int { + ret a + b + } + add(one(), one()) <=> 2 + add(add(one(), one()), one()) <=> 3 + add(one(), add(one(), one())) <=> 3 +} diff --git a/progs/tests/auto/cluster.sy b/progs/tests/auto/cluster.sy new file mode 100644 index 0000000..8f279e7 --- /dev/null +++ b/progs/tests/auto/cluster.sy @@ -0,0 +1,14 @@ +start :: fn { + +blob A { a: int } +a := A() +a.a = 0 +a.a += 1 +a.a <=> 1 +a.a *= 2 +a.a <=> 2 +a.a /= 2 +a.a <=> 1 +a.a -= 1 +a.a <=> 0 +} diff --git a/progs/tests/auto/compare_constants_equality.sy b/progs/tests/auto/compare_constants_equality.sy new file mode 100644 index 0000000..c8c399b --- /dev/null +++ b/progs/tests/auto/compare_constants_equality.sy @@ -0,0 +1,5 @@ +start :: fn { +if 1 == 2 { + + } +} diff --git a/progs/tests/auto/compare_constants_unequality.sy b/progs/tests/auto/compare_constants_unequality.sy new file mode 100644 index 0000000..8c115b4 --- /dev/null +++ b/progs/tests/auto/compare_constants_unequality.sy @@ -0,0 +1,5 @@ +start :: fn { +if 1 != 1 { + + } +} diff --git a/progs/tests/auto/compare_variable.sy b/progs/tests/auto/compare_variable.sy new file mode 100644 index 0000000..25d21f4 --- /dev/null +++ b/progs/tests/auto/compare_variable.sy @@ -0,0 +1,9 @@ +start :: fn { +a := 1 + if a == 0 { + + } + if a != 1 { + + } +} diff --git a/progs/tests/auto/conflict_markers.sy b/progs/tests/auto/conflict_markers.sy new file mode 100644 index 0000000..715a859 --- /dev/null +++ b/progs/tests/auto/conflict_markers.sy @@ -0,0 +1,11 @@ +start :: fn { + +<<<<<<< HEAD +print extern_test(4.0) +======= +print extern_test(5.0) +>>>>>>> 2 + +} + +// errors: [ErrorKind::SyntaxError(_, _), ErrorKind::GitConflictError(2, 6)] diff --git a/progs/tests/auto/constant_function.sy b/progs/tests/auto/constant_function.sy new file mode 100644 index 0000000..2ec4019 --- /dev/null +++ b/progs/tests/auto/constant_function.sy @@ -0,0 +1,4 @@ +a :: fn {} +start :: fn { + a() +} diff --git a/progs/tests/auto/constant_function_closure.sy b/progs/tests/auto/constant_function_closure.sy new file mode 100644 index 0000000..8c54249 --- /dev/null +++ b/progs/tests/auto/constant_function_closure.sy @@ -0,0 +1,13 @@ +q := 1 + +f :: fn -> int { + q += 1 + ret q +} + +start :: fn { + f() <=> 2 + f() <=> 3 + f() <=> 4 + f() <=> 5 +} diff --git a/progs/tests/auto/constant_function_complex.sy b/progs/tests/auto/constant_function_complex.sy new file mode 100644 index 0000000..6a60ebe --- /dev/null +++ b/progs/tests/auto/constant_function_complex.sy @@ -0,0 +1,19 @@ +h :: fn -> int { + ret 3 +} + +k :: fn -> int { + ret h() +} + +a :: fn -> int { + ret q() +} + +q :: fn -> int { + ret k() +} + +start :: fn { + a() <=> 3 +} diff --git a/progs/tests/auto/constants_in_inner_functions.sy b/progs/tests/auto/constants_in_inner_functions.sy new file mode 100644 index 0000000..3371393 --- /dev/null +++ b/progs/tests/auto/constants_in_inner_functions.sy @@ -0,0 +1,20 @@ +start :: fn { + +q : int = 0 + +f :: fn -> fn -> { + g :: fn { + q += 1 + } + ret g +} + +g := f() +g() +q <=> 1 +g() +q <=> 2 +g() +q <=> 3 + +} diff --git a/progs/tests/auto/div.sy b/progs/tests/auto/div.sy new file mode 100644 index 0000000..3073270 --- /dev/null +++ b/progs/tests/auto/div.sy @@ -0,0 +1,5 @@ +start :: fn { +a := 2 +a /= 2 +a <=> 1 +} diff --git a/progs/tests/auto/else_.sy b/progs/tests/auto/else_.sy new file mode 100644 index 0000000..896aeb4 --- /dev/null +++ b/progs/tests/auto/else_.sy @@ -0,0 +1,10 @@ +start :: fn { +a := 1 + res := 0 + if a == 0 { + + } else { + res = 1 + } + res <=> 1 +} diff --git a/progs/tests/auto/else_if.sy b/progs/tests/auto/else_if.sy new file mode 100644 index 0000000..18b64f6 --- /dev/null +++ b/progs/tests/auto/else_if.sy @@ -0,0 +1,12 @@ +start :: fn { +a := 1 + res := 0 + if a == 0 { + + } else if a == 1 { + res = 1 + } else { + + } + res <=> 1 +} diff --git a/progs/tests/auto/expressions.sy b/progs/tests/auto/expressions.sy new file mode 100644 index 0000000..0f6d6fc --- /dev/null +++ b/progs/tests/auto/expressions.sy @@ -0,0 +1,6 @@ +start :: fn { +1 + 1 // blargh + 2 // blargh + // HARGH + +} diff --git a/progs/tests/auto/factorial.sy b/progs/tests/auto/factorial.sy new file mode 100644 index 0000000..770bc33 --- /dev/null +++ b/progs/tests/auto/factorial.sy @@ -0,0 +1,12 @@ +factorial :: fn n: int -> int { + if n <= 1 { + ret 1 + } + ret n * factorial(n - 1) +} + +start :: fn { + factorial(5) <=> 120 + factorial(6) <=> 720 + factorial(12) <=> 479001600 +} diff --git a/progs/tests/auto/field.sy b/progs/tests/auto/field.sy new file mode 100644 index 0000000..c985297 --- /dev/null +++ b/progs/tests/auto/field.sy @@ -0,0 +1,3 @@ +start :: fn { +blob A { a: int } +} diff --git a/progs/tests/auto/field_assign.sy b/progs/tests/auto/field_assign.sy new file mode 100644 index 0000000..93837ea --- /dev/null +++ b/progs/tests/auto/field_assign.sy @@ -0,0 +1,5 @@ +start :: fn { +blob A { a: int } + a := A() + a.a = 2 +} diff --git a/progs/tests/auto/field_get.sy b/progs/tests/auto/field_get.sy new file mode 100644 index 0000000..0905f6f --- /dev/null +++ b/progs/tests/auto/field_get.sy @@ -0,0 +1,7 @@ +start :: fn { +blob A { a: int } + a := A() + a.a = 2 + a.a <=> 2 + 2 <=> a.a +} diff --git a/progs/tests/auto/in_rhs.sy b/progs/tests/auto/in_rhs.sy new file mode 100644 index 0000000..60e4873 --- /dev/null +++ b/progs/tests/auto/in_rhs.sy @@ -0,0 +1,3 @@ +start :: fn { +5 <=> 1 * 2 + 3 +} diff --git a/progs/tests/auto/instantiate.sy b/progs/tests/auto/instantiate.sy new file mode 100644 index 0000000..7d32bf9 --- /dev/null +++ b/progs/tests/auto/instantiate.sy @@ -0,0 +1,5 @@ +start :: fn { +blob A {} + a := A() + a +} diff --git a/progs/tests/auto/invalid_assign.sy b/progs/tests/auto/invalid_assign.sy new file mode 100644 index 0000000..a8b18f0 --- /dev/null +++ b/progs/tests/auto/invalid_assign.sy @@ -0,0 +1,7 @@ +start :: fn { +a := 1 +a = 0.1 +a +} + +// errors: [ErrorKind::TypeMismatch(Type::Int, Type::Float)] diff --git a/progs/tests/auto/more_types.sy b/progs/tests/auto/more_types.sy new file mode 100644 index 0000000..18d825e --- /dev/null +++ b/progs/tests/auto/more_types.sy @@ -0,0 +1,4 @@ +start :: fn { +a: (str, bool, int) = ("abc", true, 1) +a +} diff --git a/progs/tests/auto/mul.sy b/progs/tests/auto/mul.sy new file mode 100644 index 0000000..78cc14e --- /dev/null +++ b/progs/tests/auto/mul.sy @@ -0,0 +1,3 @@ +start :: fn { +(0, 1, 2) * (2, 3, 4) <=> (0, 3, 8) +} diff --git a/progs/tests/auto/multiple_fields.sy b/progs/tests/auto/multiple_fields.sy new file mode 100644 index 0000000..2a4b3c0 --- /dev/null +++ b/progs/tests/auto/multiple_fields.sy @@ -0,0 +1,11 @@ +start :: fn { +blob A { + a: int + b: int + } + a := A() + a.a = 2 + a.b = 3 + a.a + a.b <=> 5 + 5 <=> a.a + a.b +} diff --git a/progs/tests/auto/multiple_returns.sy b/progs/tests/auto/multiple_returns.sy new file mode 100644 index 0000000..8abc000 --- /dev/null +++ b/progs/tests/auto/multiple_returns.sy @@ -0,0 +1,12 @@ +start :: fn { +f := fn a: int -> int { + if a == 1 { + ret 2 + } else { + ret 3 + } + } + f(0) <=> 3 + f(1) <=> 2 + f(2) <=> 3 +} diff --git a/progs/tests/auto/negation.sy b/progs/tests/auto/negation.sy new file mode 100644 index 0000000..41388d8 --- /dev/null +++ b/progs/tests/auto/negation.sy @@ -0,0 +1,7 @@ +start :: fn { +-1 <=> 0 - 1 + -1 + 2 <=> 1 + -(1 + 2) <=> -3 + 1 + -1 <=> 0 + 2 * -1 <=> -2 +} diff --git a/progs/tests/auto/not.sy b/progs/tests/auto/not.sy new file mode 100644 index 0000000..712690a --- /dev/null +++ b/progs/tests/auto/not.sy @@ -0,0 +1,5 @@ +start :: fn { +f := fn {} + f! + +} diff --git a/progs/tests/auto/one_arg.sy b/progs/tests/auto/one_arg.sy new file mode 100644 index 0000000..9523a67 --- /dev/null +++ b/progs/tests/auto/one_arg.sy @@ -0,0 +1,5 @@ +start :: fn { +f := fn a:int { a <=> 1 } + f! 1 + +} diff --git a/progs/tests/auto/param_1.sy b/progs/tests/auto/param_1.sy new file mode 100644 index 0000000..1781eaf --- /dev/null +++ b/progs/tests/auto/param_1.sy @@ -0,0 +1,4 @@ +start :: fn { +f := fn a: int {} + f(1) +} diff --git a/progs/tests/auto/param_2.sy b/progs/tests/auto/param_2.sy new file mode 100644 index 0000000..ac5fdfd --- /dev/null +++ b/progs/tests/auto/param_2.sy @@ -0,0 +1,7 @@ +start :: fn { +add := fn a: int, b: int -> int { + ret a + b + } + add(1, 1) <=> 2 + add(10, 20) <=> 30 +} diff --git a/progs/tests/auto/param_and_return.sy b/progs/tests/auto/param_and_return.sy new file mode 100644 index 0000000..7e39775 --- /dev/null +++ b/progs/tests/auto/param_and_return.sy @@ -0,0 +1,7 @@ +start :: fn { +f := fn a: int -> int { + ret a * 2 + } + f(1) <=> 2 + f(5) <=> 10 +} diff --git a/progs/tests/auto/parenthesis.sy b/progs/tests/auto/parenthesis.sy new file mode 100644 index 0000000..b456769 --- /dev/null +++ b/progs/tests/auto/parenthesis.sy @@ -0,0 +1,3 @@ +start :: fn { +(1 + 2) * 3 <=> 9 +} diff --git a/progs/tests/auto/passing_functions.sy b/progs/tests/auto/passing_functions.sy new file mode 100644 index 0000000..d1ff70e --- /dev/null +++ b/progs/tests/auto/passing_functions.sy @@ -0,0 +1,9 @@ +start :: fn { +g := fn -> int { + ret 1 + } + f := fn inner: fn -> int -> int { + ret inner() + } + f(g) <=> 1 +} diff --git a/progs/tests/auto/passing_functions_mixed.sy b/progs/tests/auto/passing_functions_mixed.sy new file mode 100644 index 0000000..292e7ce --- /dev/null +++ b/progs/tests/auto/passing_functions_mixed.sy @@ -0,0 +1,9 @@ +start :: fn { +g := fn a: int -> int { + ret a * 2 + } + f := fn inner: fn int -> int, a: int -> int { + ret inner(a) + } + f(g, 2) <=> 4 +} diff --git a/progs/tests/auto/precedence.sy b/progs/tests/auto/precedence.sy new file mode 100644 index 0000000..0aee658 --- /dev/null +++ b/progs/tests/auto/precedence.sy @@ -0,0 +1,8 @@ +start :: fn { +f := fn a: int, b: int -> int { + ret a + b + } + 1 + f(2, 3) <=> 6 + 2 * f(2, 3) <=> 10 + f(2, 3) - (2 + 3) <=> 0 +} diff --git a/progs/tests/auto/return_1.sy b/progs/tests/auto/return_1.sy new file mode 100644 index 0000000..993f9fd --- /dev/null +++ b/progs/tests/auto/return_1.sy @@ -0,0 +1,6 @@ +start :: fn { +f := fn -> int { + ret 1 + } + f() <=> 1 +} diff --git a/progs/tests/auto/returning_closures.sy b/progs/tests/auto/returning_closures.sy new file mode 100644 index 0000000..1c4c091 --- /dev/null +++ b/progs/tests/auto/returning_closures.sy @@ -0,0 +1,24 @@ +start :: fn { + +f : fn -> fn -> int = fn -> fn -> int { + x : int = 0 + f := fn -> int { + x = x + 1 + ret x + } + f() <=> 1 + ret f +} + +a := f() +b := f() + +a() <=> 2 +a() <=> 3 + +b() <=> 2 +b() <=> 3 + +a() <=> 4 + +} diff --git a/progs/tests/auto/simple.sy b/progs/tests/auto/simple.sy new file mode 100644 index 0000000..436dcae --- /dev/null +++ b/progs/tests/auto/simple.sy @@ -0,0 +1,10 @@ +start :: fn { + +a :: 1 +a <=> 1 +b := 2 +{ + a <=> 1 + b <=> 2 +} +} diff --git a/progs/tests/auto/simple_add.sy b/progs/tests/auto/simple_add.sy new file mode 100644 index 0000000..f1952d3 --- /dev/null +++ b/progs/tests/auto/simple_add.sy @@ -0,0 +1,9 @@ +start :: fn { + +a := 0 +b := 99999 +a += 1 +a <=> 1 +b <=> 99999 + +} diff --git a/progs/tests/auto/simple_break.sy b/progs/tests/auto/simple_break.sy new file mode 100644 index 0000000..11c06ad --- /dev/null +++ b/progs/tests/auto/simple_break.sy @@ -0,0 +1,12 @@ +start :: fn { + +a := 0 +for i := 0, i < 10, i += 1 { + a = a + 1 + if i == 2 { + break + } +} +a <=> 3 + +} diff --git a/progs/tests/auto/simple_continue.sy b/progs/tests/auto/simple_continue.sy new file mode 100644 index 0000000..ac2bf81 --- /dev/null +++ b/progs/tests/auto/simple_continue.sy @@ -0,0 +1,12 @@ +start :: fn { + +a := 0 +for i := 0, i < 4, i += 1 { + if i == 2 { + continue + } + a = a + 1 +} +a <=> 3 + +} diff --git a/progs/tests/auto/simple_sub.sy b/progs/tests/auto/simple_sub.sy new file mode 100644 index 0000000..5dad340 --- /dev/null +++ b/progs/tests/auto/simple_sub.sy @@ -0,0 +1,9 @@ +start :: fn { + +a := 0 +b := 99999 +a -= 1 +a <=> -1 +b <=> 99999 + +} diff --git a/progs/tests/auto/simplest.sy b/progs/tests/auto/simplest.sy new file mode 100644 index 0000000..5669dc0 --- /dev/null +++ b/progs/tests/auto/simplest.sy @@ -0,0 +1,4 @@ +start :: fn { +f := fn {} + f() +} diff --git a/progs/tests/auto/single_variable.sy b/progs/tests/auto/single_variable.sy new file mode 100644 index 0000000..00217d2 --- /dev/null +++ b/progs/tests/auto/single_variable.sy @@ -0,0 +1,4 @@ +start :: fn { +a := 1 + a <=> 1 +} diff --git a/progs/tests/auto/stack_ordering.sy b/progs/tests/auto/stack_ordering.sy new file mode 100644 index 0000000..85a36bd --- /dev/null +++ b/progs/tests/auto/stack_ordering.sy @@ -0,0 +1,6 @@ +start :: fn { +a := 1 + b := 2 + b <=> 2 + a <=> 1 +} diff --git a/progs/tests/auto/strange.sy b/progs/tests/auto/strange.sy new file mode 100644 index 0000000..c495041 --- /dev/null +++ b/progs/tests/auto/strange.sy @@ -0,0 +1,15 @@ +start :: fn { + +a := 0 +{ + b := 99999 + { + a := 99999 + a + } + b + a -= 1 +} +a <=> -1 + +} diff --git a/progs/tests/auto/sub.sy b/progs/tests/auto/sub.sy new file mode 100644 index 0000000..755ae67 --- /dev/null +++ b/progs/tests/auto/sub.sy @@ -0,0 +1,3 @@ +start :: fn { +(1, -2, 3, -4) - (4, 3, -2, -1) <=> (-3, 1, 1, -5) +} diff --git a/progs/tests/auto/terms_and_factors.sy b/progs/tests/auto/terms_and_factors.sy new file mode 100644 index 0000000..1fef724 --- /dev/null +++ b/progs/tests/auto/terms_and_factors.sy @@ -0,0 +1,4 @@ +start :: fn { +1 + 1 * 2 <=> 3 + 1 * 2 + 3 <=> 5 +} diff --git a/progs/tests/auto/three_arg.sy b/progs/tests/auto/three_arg.sy new file mode 100644 index 0000000..d948fa0 --- /dev/null +++ b/progs/tests/auto/three_arg.sy @@ -0,0 +1,5 @@ +start :: fn { +f := fn a:int, b:int, c:int { c <=> 13 } + f! 1, 1 + 2, 1 + 4 * 3 + +} diff --git a/progs/tests/auto/two_arg.sy b/progs/tests/auto/two_arg.sy new file mode 100644 index 0000000..60645b5 --- /dev/null +++ b/progs/tests/auto/two_arg.sy @@ -0,0 +1,5 @@ +start :: fn { +f := fn a:int, b:int { b <=> 3 } + f! 1, 1 + 2 + +} diff --git a/progs/tests/auto/two_variables.sy b/progs/tests/auto/two_variables.sy new file mode 100644 index 0000000..9ae183f --- /dev/null +++ b/progs/tests/auto/two_variables.sy @@ -0,0 +1,6 @@ +start :: fn { +a := 1 + b := 2 + a <=> 1 + b <=> 2 +} diff --git a/progs/tests/auto/types.sy b/progs/tests/auto/types.sy new file mode 100644 index 0000000..c045b34 --- /dev/null +++ b/progs/tests/auto/types.sy @@ -0,0 +1,4 @@ +start :: fn { +a: (int, float, int) = (1, 1., 1) +a +} diff --git a/progs/tests/auto/uncallable_type.sy b/progs/tests/auto/uncallable_type.sy new file mode 100644 index 0000000..06ff71a --- /dev/null +++ b/progs/tests/auto/uncallable_type.sy @@ -0,0 +1,9 @@ +start :: fn { + + f := fn i: int { + i() + } + f +} + +// errors: [ErrorKind::InvalidProgram] diff --git a/progs/tests/auto/wrong_params.sy b/progs/tests/auto/wrong_params.sy new file mode 100644 index 0000000..6b56e90 --- /dev/null +++ b/progs/tests/auto/wrong_params.sy @@ -0,0 +1,7 @@ +start :: fn { + + f : fn -> int = fn a: int -> int {} +f +} + +// errors: [ErrorKind::TypeMismatch(_, _), ErrorKind::TypeMismatch(Type::Void, Type::Int)] diff --git a/progs/tests/auto/wrong_ret.sy b/progs/tests/auto/wrong_ret.sy new file mode 100644 index 0000000..81f2517 --- /dev/null +++ b/progs/tests/auto/wrong_ret.sy @@ -0,0 +1,7 @@ +start :: fn { + + f : fn -> int = fn {} +f +} + +// errors: [ErrorKind::TypeMismatch(_, _)] diff --git a/progs/tests/faulty.sy b/progs/tests/faulty.sy index 369b8ff..ea1b40d 100644 --- a/progs/tests/faulty.sy +++ b/progs/tests/faulty.sy @@ -1,3 +1,5 @@ asdflökja;;;; 123 asd + +// errors: [ErrorKind::SyntaxError(_, _)] diff --git a/progs/tests/fib.sy b/progs/tests/fib.sy index 1dde6a8..62f38e7 100644 --- a/progs/tests/fib.sy +++ b/progs/tests/fib.sy @@ -1,9 +1,11 @@ -a := 0 -b := 1 +start :: fn { + a := 0 + b := 1 -for i := 0, i < 90, i = i + 1 { - c := a - a = b - b = c + b + for i := 0, i < 90, i = i + 1 { + c := a + a = b + b = c + b + } + a <=> 2880067194370816120 } -a <=> 2880067194370816120 diff --git a/progs/tests/for.sy b/progs/tests/for.sy index a9f8cd2..285cbc3 100644 --- a/progs/tests/for.sy +++ b/progs/tests/for.sy @@ -1,19 +1,21 @@ -a := 0 -for i := 0, i < 3, i = i + 1 { - a = a + i -} -a <=> 3 +start :: fn { + a := 0 + for i := 0, i < 3, i = i + 1 { + a = a + i + } + a <=> 3 -a = 0 -for i := 0, i <= 3, i = i + 1 { - a = a + i -} -a <=> 6 + a = 0 + for i := 0, i <= 3, i = i + 1 { + a = a + i + } + a <=> 6 -a = 0 -for i := 0, i < 3, i = i + 1 { - for j := 0, j < 3, j = j + 1 { - a = a + i * j + a = 0 + for i := 0, i < 3, i = i + 1 { + for j := 0, j < 3, j = j + 1 { + a = a + i * j + } } + a <=> 9 } -a <=> 9 diff --git a/progs/tests/scoping.sy b/progs/tests/scoping.sy index f8e0b00..dfcf92c 100644 --- a/progs/tests/scoping.sy +++ b/progs/tests/scoping.sy @@ -1,14 +1,16 @@ -a : int = 1 -{ +start :: fn { + a : int = 1 + { + a <=> 1 + a : int = a + a + a <=> 2 + } a <=> 1 - a : int = a + a - a <=> 2 -} -a <=> 1 -{ - a = 2 - a : int = 1 - a + { + a = 2 + a : int = 1 + a + } + a <=> 2 } -a <=> 2 diff --git a/progs/tests/simple.sy b/progs/tests/simple.sy deleted file mode 100644 index 84bc86d..0000000 --- a/progs/tests/simple.sy +++ /dev/null @@ -1,23 +0,0 @@ -// -// import A - -// -f :: fn { - g! - print q -} - -// -q :: 1 - -// -a := 1 - -qq :: fn { - g! - print q -} - - -// Steg 1: Hitta sektioner -// Dela sektioner, compilera felera sektioner efter varandra diff --git a/src/lib.rs b/src/lib.rs index 03abd48..6b1bc08 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -874,37 +874,6 @@ mod tests { panic!(msg); } - #[macro_export] - macro_rules! test_string { - ($fn:ident, $prog:literal) => { - #[test] - fn $fn() { - crate::tests::panic_after(std::time::Duration::from_millis(500), || { - let prog = std::concat!("start :: fn {", $prog, "\n{}\n}\n"); - match $crate::run_string(&prog, true, Vec::new()) { - Ok(()) => {}, - Err(errs) => { - for e in errs.iter() { - eprintln!("{}", e); - } - eprintln!(" {} - failed\n", stringify!($fn)); - unreachable!(); - } - } - }); - } - }; - ($fn:ident, $prog:literal, $errs:tt) => { - #[test] - fn $fn() { - crate::tests::panic_after(std::time::Duration::from_millis(500), || { - let prog = std::concat!("start :: fn {", $prog, "\n{}\n}\n"); - $crate::assert_errs!($crate::run_string(&prog, true, Vec::new()), $errs); - }) - } - } - } - #[macro_export] macro_rules! test_file { ($fn:ident, $path:literal) => { @@ -918,6 +887,7 @@ mod tests { #[test] fn $fn() { use crate::error::ErrorKind; + use crate::Type; let file = std::path::Path::new($path); let res = crate::run_file(&file, true, Vec::new()); @@ -927,518 +897,4 @@ mod tests { } sylt_macro::find_tests!(); - - #[test] - fn unreachable_token() { - assert_errs!(run_string("\n", true, Vec::new()), [ErrorKind::Unreachable]); - } - - #[test] - fn assign_to_constant() { - assert_errs!(run_string("a :: 2\na = 2", true, Vec::new()), [ErrorKind::SyntaxError(_, _)]); - } - - #[test] - fn assign_to_constant_upvalue() { - assert_errs!(run_string("a :: 2\nq :: fn { a = 2 }\nq()\na", true, Vec::new()), [ErrorKind::SyntaxError(_, _)]); - } - - #[test] - fn undefined_blob() { - 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 -} -a - "; - assert_errs!(run_string(prog, true, Vec::new()), [ErrorKind::InvalidProgram, ErrorKind::TypeError(_, _)]); - } - - #[test] - fn unused_variable() { - assert_errs!(run_string("a := 1", true, Vec::new()), [ErrorKind::SyntaxError(1, _)]); - } - - #[test] - fn unused_upvalue() { - assert_errs!(run_string("a := 1\nf :: fn { a = 2 }\nf()", true, Vec::new()), [ErrorKind::SyntaxError(1, _)]); - } - - #[test] - fn unused_function() { - assert_errs!(run_string("a := 1\nf := fn { a }\n", true, Vec::new()), [ErrorKind::SyntaxError(2, _)]); - } - - macro_rules! test_multiple { - ($mod:ident, $( $fn:ident : $prog:literal ),+ $( , )? ) => { - mod $mod { - $( test_string!($fn, $prog); )+ - } - } - } - - test_multiple!( - order_of_operations, - terms_and_factors: "1 + 1 * 2 <=> 3 - 1 * 2 + 3 <=> 5", - in_rhs: "5 <=> 1 * 2 + 3", - parenthesis: "(1 + 2) * 3 <=> 9", - negation: "-1 <=> 0 - 1 - -1 + 2 <=> 1 - -(1 + 2) <=> -3 - 1 + -1 <=> 0 - 2 * -1 <=> -2", - ); - - test_multiple!( - variables, - single_variable: "a := 1 - a <=> 1", - two_variables: "a := 1 - b := 2 - a <=> 1 - b <=> 2", - stack_ordering: "a := 1 - b := 2 - b <=> 2 - a <=> 1", - assignment: "a := 1 - b := 2 - a = b - a <=> 2 - b <=> 2", - ); - - test_multiple!( - if_, - compare_constants_equality: "if 1 == 2 { - - }", - compare_constants_unequality: "if 1 != 1 { - - }", - compare_variable: "a := 1 - if a == 0 { - - } - if a != 1 { - - }", - else_: "a := 1 - res := 0 - if a == 0 { - - } else { - res = 1 - } - res <=> 1", - else_if: "a := 1 - res := 0 - if a == 0 { - - } else if a == 1 { - res = 1 - } else { - - } - res <=> 1", - ); - - test_multiple!( - fun, - simplest: "f := fn {} - f()", - param_1: "f := fn a: int {} - f(1)", - return_1: "f := fn -> int { - ret 1 - } - f() <=> 1", - param_and_return: "f := fn a: int -> int { - ret a * 2 - } - f(1) <=> 2 - f(5) <=> 10", - param_2: "add := fn a: int, b: int -> int { - ret a + b - } - add(1, 1) <=> 2 - add(10, 20) <=> 30", - calls_inside_calls: "one := fn -> int { - ret 1 - } - add := fn a: int, b: int -> int { - ret a + b - } - add(one(), one()) <=> 2 - add(add(one(), one()), one()) <=> 3 - add(one(), add(one(), one())) <=> 3", - passing_functions: "g := fn -> int { - ret 1 - } - f := fn inner: fn -> int -> int { - ret inner() - } - f(g) <=> 1", - passing_functions_mixed: "g := fn a: int -> int { - ret a * 2 - } - f := fn inner: fn int -> int, a: int -> int { - ret inner(a) - } - f(g, 2) <=> 4", - multiple_returns: "f := fn a: int -> int { - if a == 1 { - ret 2 - } else { - ret 3 - } - } - f(0) <=> 3 - f(1) <=> 2 - f(2) <=> 3", - precedence: "f := fn a: int, b: int -> int { - ret a + b - } - 1 + f(2, 3) <=> 6 - 2 * f(2, 3) <=> 10 - f(2, 3) - (2 + 3) <=> 0", - factorial: "factorial : fn int -> int = fn n: int -> int { - if n <= 1 { - ret 1 - } - ret n * factorial(n - 1) - } - factorial(5) <=> 120 - factorial(6) <=> 720 - factorial(12) <=> 479001600", - - returning_closures: " -f : fn -> fn -> int = fn -> fn -> int { - x : int = 0 - f := fn -> int { - x = x + 1 - ret x - } - f() <=> 1 - ret f -} - -a := f() -b := f() - -a() <=> 2 -a() <=> 3 - -b() <=> 2 -b() <=> 3 - -a() <=> 4 -", - ); - - test_multiple!( - blob, - simple: "blob A {}", - instantiate: "blob A {} - a := A() - a", - field: "blob A { a: int }", - field_assign: "blob A { a: int } - a := A() - a.a = 2", - field_get: "blob A { a: int } - a := A() - a.a = 2 - a.a <=> 2 - 2 <=> a.a", - multiple_fields: "blob A { - a: int - b: int - } - a := A() - a.a = 2 - a.b = 3 - a.a + a.b <=> 5 - 5 <=> a.a + a.b", - blob_infer: " -blob A { } -a : A = A() -a -", - ); - - test_multiple!(tuples, - add: "(1, 2, 3, 4) + (4, 3, 2, 1) <=> (5, 5, 5, 5)", - sub: "(1, -2, 3, -4) - (4, 3, -2, -1) <=> (-3, 1, 1, -5)", - mul: "(0, 1, 2) * (2, 3, 4) <=> (0, 3, 8)", - types: "a: (int, float, int) = (1, 1., 1)\na", - more_types: "a: (str, bool, int) = (\"abc\", true, 1)\na", - ); - - test_file!(scoping, "progs/tests/scoping.sy"); - test_file!(for_, "progs/tests/for.sy"); - - test_multiple!( - op_assign, - add: "a := 1\na += 1\na <=> 2", - sub: "a := 2\na -= 1\na <=> 1", - mul: "a := 2\na *= 2\na <=> 4", - div: "a := 2\na /= 2\na <=> 1", - cluster: " -blob A { a: int } -a := A() -a.a = 0 -a.a += 1 -a.a <=> 1 -a.a *= 2 -a.a <=> 2 -a.a /= 2 -a.a <=> 1 -a.a -= 1 -a.a <=> 0" - ); - - test_multiple!( - fancy_call, - not: "f := fn {}\n f!\n", - one_arg: "f := fn a:int { a <=> 1 }\n f! 1\n", - two_arg: "f := fn a:int, b:int { b <=> 3 }\n f! 1, 1 + 2\n", - three_arg: "f := fn a:int, b:int, c:int { c <=> 13 }\n f! 1, 1 + 2, 1 + 4 * 3\n", - ); - - test_multiple!( - newline_regression, - simple: "a := 1 // blargh \na += 1 // blargh \n a <=> 2 // HARGH", - expressions: "1 + 1 // blargh \n 2 // blargh \n // HARGH \n", - ); - - test_multiple!( - break_and_continue, - simple_break: " -a := 0 -for i := 0, i < 10, i += 1 { - a = a + 1 - if i == 2 { - break - } -} -a <=> 3 -", - - simple_continue: " -a := 0 -for i := 0, i < 4, i += 1 { - if i == 2 { - continue - } - a = a + 1 -} -a <=> 3 -", - - advanced_break: " -a := 0 -for i := 0, i < 10, i += 1 { - q := 0 - qq := 0 - qqq := 0 - qqqq := 0 - - a = a + 1 - if i == 2 { - break - } - - q - qq - qqq - qqqq -} -a <=> 3 -", - - advanced_continue: " -a := 0 -for i := 0, i < 4, i += 1 { - q := 0 - qq := 0 - qqq := 0 - qqqq := 0 - - if i == 2 { - continue - } - a = a + 1 - - q - qq - qqq - qqqq -} -a <=> 3 -", - ); - - test_multiple!( - read_constants, - simple: " -a :: 1 -a <=> 1 -b := 2 -{ - a <=> 1 - b <=> 2 -}", - ); - - test_multiple!( - assignment_op_regression, - simple_add: " -a := 0 -b := 99999 -a += 1 -a <=> 1 -b <=> 99999 -", - - simple_sub: " -a := 0 -b := 99999 -a -= 1 -a <=> -1 -b <=> 99999 -", - - strange: " -a := 0 -{ - b := 99999 - { - a := 99999 - a - } - b - a -= 1 -} -a <=> -1 -", - ); - - test_multiple!( - declaration_order, - blob_simple: " -a := A() -a - -blob A { - a: int -} -", - - blob_complex: " -a := A() -b := B() -c := C() -b2 := B() - -a -b -c -b2 - -blob A { - c: C -} -blob C { } -blob B { } -", - - blob_infer: " -blob A { } - -a : A = A() -a -", - - - constant_function: " -a() -a :: fn {} -", - - constant_function_complex: " -h :: fn -> int { - ret 3 -} - -a() <=> 3 - -k :: fn -> int { - ret h() -} - -a :: fn -> int { - ret q() -} - -q :: fn -> int { - ret k() -} -", - - constant_function_closure: " -q := 1 - -f :: fn -> int { - q += 1 - ret q -} - -f() <=> 2 -f() <=> 3 -f() <=> 4 -f() <=> 5 -", - - constants_in_inner_functions: " -q : int = 0 - -f :: fn -> fn -> { - g :: fn { - q += 1 - } - ret g -} - -g := f() -g() -q <=> 1 -g() -q <=> 2 -g() -q <=> 3 -", - - ); - - test_string!(conflict_markers, " -<<<<<<< HEAD -print extern_test(4.0) -======= -print extern_test(5.0) ->>>>>>> 2 -", - [ErrorKind::SyntaxError(_, _), ErrorKind::GitConflictError(2, 6)] - ); - } diff --git a/src/vm.rs b/src/vm.rs index f5e5c58..d056ded 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -824,29 +824,3 @@ impl VM { } } } - -#[cfg(test)] -mod tests { - mod typing { - use crate::error::ErrorKind; - use crate::{test_string, Type}; - - test_string!(uncallable_type, " - f := fn i: int { - i() - } - f", - [ErrorKind::InvalidProgram]); - - test_string!(invalid_assign, "a := 1\na = 0.1\na", - [ErrorKind::TypeMismatch(Type::Int, Type::Float)]); - - test_string!(wrong_params, " - f : fn -> int = fn a: int -> int {}\nf", - [ErrorKind::TypeMismatch(_, _), ErrorKind::TypeMismatch(Type::Void, Type::Int)]); - - test_string!(wrong_ret, " - f : fn -> int = fn {}\nf", - [ErrorKind::TypeMismatch(_, _)]); - } -} -- cgit v1.2.1 From d31c62339c819649d98ff789797ae22d2a0b97d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Fri, 5 Mar 2021 19:28:16 +0100 Subject: fix some warnings --- src/lib.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 6b1bc08..adb7eed 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -802,10 +802,6 @@ pub struct Prog { #[cfg(test)] mod tests { - use crate::error::ErrorKind; - - use super::run_string; - #[macro_export] macro_rules! assert_errs { ($result:expr, [ $( $kind:pat ),* ]) => { @@ -887,6 +883,7 @@ mod tests { #[test] fn $fn() { use crate::error::ErrorKind; + #[allow(unused_imports)] use crate::Type; let file = std::path::Path::new($path); -- cgit v1.2.1 From 84d350d3793355da8a7caa4df57d08e38e1f532f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Fri, 5 Mar 2021 19:29:03 +0100 Subject: fix all warnings --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index adb7eed..afde461 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -842,6 +842,7 @@ mod tests { use owo_colors::OwoColorize; // Shamelessly stolen from https://github.com/rust-lang/rfcs/issues/2798 + #[allow(dead_code)] pub fn panic_after(d: Duration, f: F) -> T where T: Send + 'static, -- cgit v1.2.1 From 0b15a38e324c3940318df462812c42f74a544267 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Fri, 5 Mar 2021 19:46:11 +0100 Subject: correct conflict marker test --- progs/tests/auto/conflict_markers.sy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/progs/tests/auto/conflict_markers.sy b/progs/tests/auto/conflict_markers.sy index 715a859..167a751 100644 --- a/progs/tests/auto/conflict_markers.sy +++ b/progs/tests/auto/conflict_markers.sy @@ -8,4 +8,4 @@ print extern_test(5.0) } -// errors: [ErrorKind::SyntaxError(_, _), ErrorKind::GitConflictError(2, 6)] +// errors: [ErrorKind::SyntaxError(_, _), ErrorKind::GitConflictError(3, 7)] -- cgit v1.2.1 From b1fab16befb78232d7a913f58beef639c5891e26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Fri, 5 Mar 2021 19:47:00 +0100 Subject: set no_print in tests --- progs/bench/fib.sy | 6 +++--- progs/bench/fib_iter.sy | 3 ++- progs/bench/sum.sy | 3 ++- src/lib.rs | 8 ++++---- sylt_macro/src/lib.rs | 44 +++++++++++++++++++++++++++++++++++++------- 5 files changed, 48 insertions(+), 16 deletions(-) diff --git a/progs/bench/fib.sy b/progs/bench/fib.sy index 76c3af7..ad10e20 100644 --- a/progs/bench/fib.sy +++ b/progs/bench/fib.sy @@ -8,7 +8,7 @@ fib :: fn a:int -> int { } // 23 is around where things start getting slow. start :: fn { - //TODO pass arguments to skip debug printing. this test is very slow otherwise - - // fib(23) <=> 28657 + fib(23) <=> 28657 } + +// flags: no_print diff --git a/progs/bench/fib_iter.sy b/progs/bench/fib_iter.sy index f82d6f8..7ed1021 100644 --- a/progs/bench/fib_iter.sy +++ b/progs/bench/fib_iter.sy @@ -1,7 +1,6 @@ // A Fibonacci implementation that is a little // less awful. But we run it 1000 times instead. start :: fn { - j := 0 for , j < 1000, j = j + 1 { a := 0 @@ -15,3 +14,5 @@ start :: fn { a <=> 12586269025 } } + +// flags: no_print diff --git a/progs/bench/sum.sy b/progs/bench/sum.sy index 39252cd..76fe392 100644 --- a/progs/bench/sum.sy +++ b/progs/bench/sum.sy @@ -1,9 +1,10 @@ // Adds the numbers 0 to 100000 start :: fn { - sum := 0 for i := 0, i <= 100000, i += 1 { sum += i } sum <=> 5000050000 } + +// flags: no_print diff --git a/src/lib.rs b/src/lib.rs index afde461..e94eaad 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -873,14 +873,14 @@ mod tests { #[macro_export] macro_rules! test_file { - ($fn:ident, $path:literal) => { + ($fn:ident, $path:literal, $print:expr) => { #[test] fn $fn() { let file = std::path::Path::new($path); - crate::run_file(&file, true, Vec::new()).unwrap(); + crate::run_file(&file, $print, Vec::new()).unwrap(); } }; - ($fn:ident, $path:literal, $errs:tt) => { + ($fn:ident, $path:literal, $print:expr, $errs:tt) => { #[test] fn $fn() { use crate::error::ErrorKind; @@ -888,7 +888,7 @@ mod tests { use crate::Type; let file = std::path::Path::new($path); - let res = crate::run_file(&file, true, Vec::new()); + let res = crate::run_file(&file, $print, Vec::new()); $crate::assert_errs!(res, $errs); } }; diff --git a/sylt_macro/src/lib.rs b/sylt_macro/src/lib.rs index 96f7112..95b79c6 100644 --- a/sylt_macro/src/lib.rs +++ b/sylt_macro/src/lib.rs @@ -160,13 +160,41 @@ pub fn link(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream { proc_macro::TokenStream::from(tokens) } -fn parse_test(contents: String) -> Option { +struct TestSettings { + errors: Option, + print: bool, +} + +impl Default for TestSettings { + fn default() -> Self { + Self { + errors: None, + print: true, + } + } +} + +fn parse_test_settings(contents: String) -> TestSettings { + let mut settings = TestSettings::default(); + for line in contents.split("\n") { if line.starts_with("// errors: ") { - return Some(line.strip_prefix("// errors: ").unwrap().to_string()); + settings.errors = Some(line.strip_prefix("// errors: ").unwrap().to_string()); + } else if line.starts_with("// flags: ") { + for flag in line.split(" ").skip(2) { + match flag { + "no_print" => { + settings.print = false; + } + _ => { + panic!("Unknown test flag '{}'", flag); + } + } + } } } - None + + settings } fn find_test_paths(directory: &Path) -> proc_macro2::TokenStream { @@ -188,14 +216,16 @@ fn find_test_paths(directory: &Path) -> proc_macro2::TokenStream { let path_string = path.to_str().unwrap(); let test_name = format_ident!("file_{}", file_name.replace(".sy", "")); - let tokens = if let Some(wanted_err) = parse_test(std::fs::read_to_string(path.clone()).unwrap()) { - let wanted_err: proc_macro2::TokenStream = wanted_err.parse().unwrap(); + let settings = parse_test_settings(std::fs::read_to_string(path.clone()).unwrap()); + let print = settings.print; + let tokens = if let Some(wanted_errs) = settings.errors { + let wanted_errs: proc_macro2::TokenStream = wanted_errs.parse().unwrap(); quote! { - test_file!(#test_name, #path_string, #wanted_err); + test_file!(#test_name, #path_string, #print, #wanted_errs); } } else { quote! { - test_file!(#test_name, #path_string); + test_file!(#test_name, #path_string, #print); } }; -- cgit v1.2.1 From 57f02d45b7e6ec65c3f2055a2cc4b2c2737167d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Fri, 5 Mar 2021 19:49:49 +0100 Subject: actual error on invalid outer code --- progs/tests/faulty.sy | 2 +- src/compiler.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/progs/tests/faulty.sy b/progs/tests/faulty.sy index ea1b40d..67605d2 100644 --- a/progs/tests/faulty.sy +++ b/progs/tests/faulty.sy @@ -2,4 +2,4 @@ asdflökja;;;; 123 asd -// errors: [ErrorKind::SyntaxError(_, _)] +// errors: [ErrorKind::SyntaxError(_, _), ErrorKind::SyntaxError(_, _), ErrorKind::SyntaxError(_, _)] diff --git a/src/compiler.rs b/src/compiler.rs index 69ce39a..9f9d6ef 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -1737,7 +1737,8 @@ impl Compiler { (None, ..) => {} (a, b, c) => { - panic!(format!("Unknown outer token sequence: {:?} {:?} {:?}", a, b, c)); + let msg = format!("Unknown outer token sequence: {:?} {:?} {:?}", a, b, c); + error!(self, msg); } } } -- cgit v1.2.1 From dd38069bc1f8b696e8f0c50f43e0e7954729acf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Fri, 5 Mar 2021 20:12:39 +0100 Subject: better errors on invalid outer tokens --- progs/tests/faulty.sy | 2 +- src/compiler.rs | 12 ++++++++---- src/sectionizer.rs | 2 ++ 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/progs/tests/faulty.sy b/progs/tests/faulty.sy index 67605d2..ea1b40d 100644 --- a/progs/tests/faulty.sy +++ b/progs/tests/faulty.sy @@ -2,4 +2,4 @@ asdflökja;;;; 123 asd -// errors: [ErrorKind::SyntaxError(_, _), ErrorKind::SyntaxError(_, _), ErrorKind::SyntaxError(_, _)] +// errors: [ErrorKind::SyntaxError(_, _)] diff --git a/src/compiler.rs b/src/compiler.rs index 9f9d6ef..16887a0 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -1571,8 +1571,8 @@ impl Compiler { (Token::Newline, ..) => {} - _ => { - error!(self, "Invalid outer statement."); + (a, b, c, d) => { + error!(self, format!("Unknown outer token sequence: {:?} {:?} {:?} {:?}.", a, b, c, d)) } } } @@ -1686,7 +1686,7 @@ impl Compiler { pub(crate) fn compile(&mut self, name: &str, file: &Path, functions: &[(String, RustFunction)]) -> Result> { for section in 0..self.sections.len() { self.init_section(section); - let section = &self.sections[section]; + let section = &mut self.sections[section]; match (section.tokens.get(0), section.tokens.get(1), section.tokens.get(2)) { (Some((Token::Use, _)), Some((Token::Identifier(name), _)), ..) => { @@ -1737,7 +1737,8 @@ impl Compiler { (None, ..) => {} (a, b, c) => { - let msg = format!("Unknown outer token sequence: {:?} {:?} {:?}", a, b, c); + section.faulty = true; + let msg = format!("Unknown outer token sequence: {:?} {:?} {:?}. Expected 'use', function, blob or variable.", a, b, c); error!(self, msg); } } @@ -1755,6 +1756,9 @@ impl Compiler { let mut block = Block::new(name, file); for section in 0..self.sections.len() { self.init_section(section); + if self.sections[section].faulty { + continue; + } while !matches!(self.peek(), Token::EOF | Token::Use) { self.outer_statement(&mut block); expect!(self, Token::Newline | Token::EOF, diff --git a/src/sectionizer.rs b/src/sectionizer.rs index c9cfcd5..8c5e238 100644 --- a/src/sectionizer.rs +++ b/src/sectionizer.rs @@ -6,6 +6,7 @@ use std::path::{Path, PathBuf}; pub struct Section { pub tokens: Vec, pub path: PathBuf, + pub faulty: bool, } impl Section { @@ -13,6 +14,7 @@ impl Section { Self { tokens: Vec::from(tokens), path, + faulty: false, } } } -- cgit v1.2.1 From ba7ebb200cc5560ba0a2237df4a4985fe927b08c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Fri, 5 Mar 2021 21:08:27 +0100 Subject: almost working capturing variables --- progs/tests/auto/constant_function_closure.sy | 2 +- src/compiler.rs | 19 ++++--- src/vm.rs | 77 ++++++++++++++++++--------- 3 files changed, 64 insertions(+), 34 deletions(-) diff --git a/progs/tests/auto/constant_function_closure.sy b/progs/tests/auto/constant_function_closure.sy index 8c54249..6c7f0d7 100644 --- a/progs/tests/auto/constant_function_closure.sy +++ b/progs/tests/auto/constant_function_closure.sy @@ -1,4 +1,4 @@ -q := 1 +q : int = 1 f :: fn -> int { q += 1 diff --git a/src/compiler.rs b/src/compiler.rs index 16887a0..9c8f830 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -227,11 +227,13 @@ impl Variable { } } +#[derive(Debug)] enum LoopOp { Continue, Break, } +#[derive(Debug)] struct Frame { loops: Vec>, stack: Vec, @@ -1146,7 +1148,6 @@ impl Compiler { assert!(var.mutable); self.expression(block); - add_op(self, block, Op::AssignLocal(var.slot)); self.stack_mut()[var.slot].active = true; } else { // Local @@ -1684,6 +1685,10 @@ impl Compiler { } pub(crate) fn compile(&mut self, name: &str, file: &Path, functions: &[(String, RustFunction)]) -> Result> { + let main = Variable::new("/main/", false, Type::Void); + let slot = self.define(main).unwrap(); + self.frame_mut().stack[slot].read = true; + for section in 0..self.sections.len() { self.init_section(section); let section = &mut self.sections[section]; @@ -1715,7 +1720,8 @@ impl Compiler { if let Ok(ty) = self.parse_type() { let is_mut = self.peek() == Token::Equal; let var = Variable::new(&name, is_mut, ty); - let _ = self.define(var); + let slot = self.define(var).unwrap(); + self.frame_mut().stack[slot].active = true; } else { error!(self, format!("Failed to parse type global '{}'.", name)); } @@ -1724,13 +1730,15 @@ impl Compiler { (Some((Token::Identifier(name), _)), Some((Token::ColonColon, _)), ..) => { let var = Variable::new(name, false, Type::Unknown); - let _ = self.define(var); + let slot = self.define(var).unwrap(); + self.frame_mut().stack[slot].active = true; } (Some((Token::Identifier(name), _)), Some((Token::ColonEqual, _)), ..) => { let var = Variable::new(name, true, Type::Unknown); - let _ = self.define(var); + let slot = self.define(var).unwrap(); + self.frame_mut().stack[slot].active = true; } @@ -1750,9 +1758,6 @@ impl Compiler { .enumerate() .map(|(i, (s, f))| (s, (i, f))) .collect(); - let main = Variable::new("/main/", false, Type::Void); - let _ = self.define(main); - let mut block = Block::new(name, file); for section in 0..self.sections.len() { self.init_section(section); diff --git a/src/vm.rs b/src/vm.rs index d056ded..2237896 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -6,7 +6,7 @@ use std::rc::Rc; use owo_colors::OwoColorize; -use crate::{Block, Op, Prog, UpValue, Value, op}; +use crate::{Block, BlockLinkState, Op, Prog, UpValue, Value, op}; use crate::error::{Error, ErrorKind}; use crate::RustFunction; use crate::Type; @@ -553,36 +553,37 @@ impl VM { match self.constant(value).clone() { Value::Function(_, block) => { self.push(Value::Function(Vec::new(), block.clone())); + if !matches!(block.borrow().linking, BlockLinkState::Linked) { + if block.borrow().needs_linking() { + error!(self, + ErrorKind::InvalidProgram, + format!("Calling function '{}' before all captured variables are declared.", + block.borrow().name)); + } - if block.borrow().needs_linking() { - 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 { - types.push(ty.clone()); - } else { - types.push(Type::from(&self.stack[*slot])); + let mut types = Vec::new(); + for (slot, is_up, ty) in block.borrow().upvalues.iter() { + if *is_up { + types.push(ty.clone()); + } else { + types.push(Type::from(&self.stack[*slot])); + } } - } - let mut block_mut = block.borrow_mut(); - for (i, (_, is_up, ty)) in block_mut.upvalues.iter_mut().enumerate() { - if *is_up { continue; } + let mut block_mut = block.borrow_mut(); + for (i, (_, is_up, ty)) in block_mut.upvalues.iter_mut().enumerate() { + if *is_up { continue; } - let suggestion = &types[i]; - if matches!(ty, Type::Unknown) { - *ty = suggestion.clone(); - } else { - if ty != suggestion { - error!(self, ErrorKind::CannotInfer(ty.clone(), suggestion.clone())); + let suggestion = &types[i]; + if matches!(ty, Type::Unknown) { + *ty = suggestion.clone(); + } else { + if ty != suggestion { + error!(self, ErrorKind::CannotInfer(ty.clone(), suggestion.clone())); + } } - } - }; + }; + } }, value => { self.push(value.clone()); @@ -652,6 +653,7 @@ impl VM { let inner = self.frame().block.borrow(); let ret = inner.ret(); if Type::from(&a) != *ret { + error!(self, ErrorKind::TypeMismatch(a.into(), ret.clone()), "Value does not match return type."); } @@ -679,6 +681,29 @@ impl VM { match self.constant(slot).clone() { Value::Function(_, block) => { block.borrow_mut().link(); + + let mut types = Vec::new(); + for (slot, is_up, ty) in block.borrow().upvalues.iter() { + if *is_up { + types.push(ty.clone()); + } else { + types.push(Type::from(&self.stack[*slot])); + } + } + + let mut block_mut = block.borrow_mut(); + for (i, (_, is_up, ty)) in block_mut.upvalues.iter_mut().enumerate() { + if *is_up { continue; } + + let suggestion = &types[i]; + if matches!(ty, Type::Unknown) { + *ty = suggestion.clone(); + } else { + if ty != suggestion { + error!(self, ErrorKind::CannotInfer(ty.clone(), suggestion.clone())); + } + } + } } value => { error!(self, -- cgit v1.2.1 From de7ddbe322b615eeeba17730486da4b9d024ebe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Fri, 5 Mar 2021 21:17:11 +0100 Subject: fix the hard test ;) --- src/vm.rs | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/vm.rs b/src/vm.rs index 2237896..7cfc8d3 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -236,22 +236,26 @@ impl VM { let offset = self.frame().stack_offset; let constant = self.constant(value).clone(); let value = match constant { - Value::Function(_, block) => { - let mut ups = Vec::new(); - for (slot, is_up, _) in block.borrow().upvalues.iter() { - let up = if *is_up { - if let Value::Function(local_ups, _) = &self.stack[offset] { - Rc::clone(&local_ups[*slot]) + Value::Function(ups, block) => { + if matches!(block.borrow().linking, BlockLinkState::Linked) { + Value::Function(ups.clone(), block) + } else { + let mut ups = Vec::new(); + for (slot, is_up, _) in block.borrow().upvalues.iter() { + let up = if *is_up { + if let Value::Function(local_ups, _) = &self.stack[offset] { + Rc::clone(&local_ups[*slot]) + } else { + unreachable!() + } } else { - unreachable!() - } - } else { - let slot = self.frame().stack_offset + slot; - Rc::clone(self.find_upvalue(slot)) - }; - ups.push(up); + let slot = self.frame().stack_offset + slot; + Rc::clone(self.find_upvalue(slot)) + }; + ups.push(up); + } + Value::Function(ups, block) } - Value::Function(ups, block) }, value => value, }; -- cgit v1.2.1 From 653b797aa68f8ec3a065909cff693327574fce91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Fri, 5 Mar 2021 21:23:21 +0100 Subject: remove unused build.rs --- build.rs | 28 ---------------------------- 1 file changed, 28 deletions(-) delete mode 100644 build.rs diff --git a/build.rs b/build.rs deleted file mode 100644 index 92b63ab..0000000 --- a/build.rs +++ /dev/null @@ -1,28 +0,0 @@ -use std::path::{Path, PathBuf}; - -fn find_tests(directory: &Path) -> Vec { - let mut tests = Vec::new(); - - for entry in std::fs::read_dir(directory).unwrap() { - let path = entry.unwrap().path(); - - if path.file_name().unwrap().to_str().unwrap().starts_with("_") { - continue; - } - - if path.is_dir() { - tests.append(&mut find_tests(&path)); - } else { - assert!(!path.to_str().unwrap().contains(","), "You should be ashamed."); - tests.push(path); - } - } - - tests -} - -fn main() { - let tests = find_tests(Path::new("progs/")); - let files = tests.iter().fold(String::new(), |a, b| format!("{},{}", a, b.display())); - println!("cargo:rustc-env=SCRIPTS={}", &files[1..]); -} -- cgit v1.2.1 From f0a55dd32abd243d11610c9dd0a6e1b74a1e4dae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Sun, 7 Mar 2021 14:16:24 +0100 Subject: update gitignore --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index c2a9b6f..0399f3b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ -/target +target tags -- cgit v1.2.1 From 4ddcde3072c79a96544f6fa10f26070a54632d18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Sun, 7 Mar 2021 14:16:37 +0100 Subject: cargo maintenance --- Cargo.lock | 79 +++++++++++++++++++++++---------------------------- Cargo.toml | 2 +- sylt_macro/Cargo.lock | 45 +++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 44 deletions(-) create mode 100644 sylt_macro/Cargo.lock diff --git a/Cargo.lock b/Cargo.lock index 6d4b83b..31ff301 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -31,9 +31,9 @@ checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] name = "bstr" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "473fc6b38233f9af7baa94fb5852dca389e3d95b8e21c8e3719301462c5d9faf" +checksum = "a40b47ad93e1a5404e6c18dec46b628214fee441c70f4ab5d6942142cc268a3d" dependencies = [ "lazy_static", "memchr", @@ -43,9 +43,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.6.0" +version = "3.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099e596ef14349721d9016f6b80dd3419ea1bf289ab9b44df8e4dfd3a005d5d9" +checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe" [[package]] name = "byteorder" @@ -79,12 +79,6 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "const_fn" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b9d6de7f49e22cf97ad17fc4036ece69300032f45f78f30b4a4482cdc3f4a6" - [[package]] name = "criterion" version = "0.3.4" @@ -144,12 +138,11 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.1" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1aaa739f95311c2c7887a76863f500026092fb1dce0161dab577e559ef3569d" +checksum = "2584f639eb95fea8c798496315b297cf81b9b58b6d30ab066a75455333cf4b12" dependencies = [ "cfg-if", - "const_fn", "crossbeam-utils", "lazy_static", "memoffset", @@ -158,9 +151,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d" +checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49" dependencies = [ "autocfg", "cfg-if", @@ -253,9 +246,9 @@ checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" [[package]] name = "js-sys" -version = "0.3.47" +version = "0.3.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cfb73131c35423a367daf8cbd24100af0d077668c8c2943f0e7dd775fef0f65" +checksum = "dc9f84f9b115ce7843d60706df1422a916680bfdfcbdb0447c5614ff9d7e4d78" dependencies = [ "wasm-bindgen", ] @@ -268,9 +261,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.85" +version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ccac4b00700875e6a07c6cde370d44d32fa01c5a65cdd2fca6858c479d28bb3" +checksum = "03b07a082330a35e43f63177cc01689da34fbffa0105e1246cf0311472cac73a" [[package]] name = "log" @@ -395,9 +388,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" dependencies = [ "proc-macro2", ] @@ -538,9 +531,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.123" +version = "1.0.124" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae" +checksum = "bd761ff957cb2a45fbb9ab3da6512de9de55872866160b23c25f1a841e99d29f" [[package]] name = "serde_cbor" @@ -554,9 +547,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.123" +version = "1.0.124" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31" +checksum = "1800f7693e94e186f5e25a28291ae1570da908aff7d97a095dec1e56ff99069b" dependencies = [ "proc-macro2", "quote", @@ -565,9 +558,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.61" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fceb2595057b6891a4ee808f70054bd2d12f0e97f1cbb78689b59f676df325a" +checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" dependencies = [ "itoa", "ryu", @@ -596,9 +589,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.60" +version = "1.0.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081" +checksum = "123a78a3596b24fee53a6464ce52d8ecbf62241e6294c7e7fe12086cd161f512" dependencies = [ "proc-macro2", "quote", @@ -616,9 +609,9 @@ dependencies = [ [[package]] name = "tinytemplate" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2ada8616fad06a2d0c455adc530de4ef57605a8120cc65da9653e0e9623ca74" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" dependencies = [ "serde", "serde_json", @@ -661,9 +654,9 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] name = "wasm-bindgen" -version = "0.2.70" +version = "0.2.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55c0f7123de74f0dab9b7d00fd614e7b19349cd1e2f5252bbe9b1754b59433be" +checksum = "7ee1280240b7c461d6a0071313e08f34a60b0365f14260362e5a2b17d1d31aa7" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -671,9 +664,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.70" +version = "0.2.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bc45447f0d4573f3d65720f636bbcc3dd6ce920ed704670118650bcd47764c7" +checksum = "5b7d8b6942b8bb3a9b0e73fc79b98095a27de6fa247615e59d096754a3bc2aa8" dependencies = [ "bumpalo", "lazy_static", @@ -686,9 +679,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.70" +version = "0.2.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b8853882eef39593ad4174dd26fc9865a64e84026d223f63bb2c42affcbba2c" +checksum = "e5ac38da8ef716661f0f36c0d8320b89028efe10c7c0afde65baffb496ce0d3b" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -696,9 +689,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.70" +version = "0.2.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4133b5e7f2a531fa413b3a1695e925038a05a71cf67e87dafa295cb645a01385" +checksum = "cc053ec74d454df287b9374ee8abb36ffd5acb95ba87da3ba5b7d3fe20eb401e" dependencies = [ "proc-macro2", "quote", @@ -709,15 +702,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.70" +version = "0.2.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd4945e4943ae02d15c13962b38a5b1e81eadd4b71214eee75af64a4d6a4fd64" +checksum = "7d6f8ec44822dd71f5f221a5847fb34acd9060535c1211b70a05844c0f6383b1" [[package]] name = "web-sys" -version = "0.3.47" +version = "0.3.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c40dc691fc48003eba817c38da7113c15698142da971298003cac3ef175680b3" +checksum = "ec600b26223b2948cedfde2a0aa6756dcf1fef616f43d7b3097aaf53a6c4d92b" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index b14b588..44b1f66 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ name = "sylt" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -logos = "0.11.4" +logos = "~0.11.4" owo-colors = { git="https://github.com/FredTheDino/owo-colors.git" } rand = "0.8" sylt_macro = { path = "sylt_macro" } diff --git a/sylt_macro/Cargo.lock b/sylt_macro/Cargo.lock new file mode 100644 index 0000000..137e02a --- /dev/null +++ b/sylt_macro/Cargo.lock @@ -0,0 +1,45 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "proc-macro2" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "sylt_macro" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.62" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "123a78a3596b24fee53a6464ce52d8ecbf62241e6294c7e7fe12086cd161f512" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" -- cgit v1.2.1 From 7d954e6f5b54bd1dda24c8aa5e968a6185d8017d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Sun, 7 Mar 2021 15:08:30 +0100 Subject: remove files --- main.sy | 13 ------------- other.sy | 11 ----------- third.sy | 5 ----- 3 files changed, 29 deletions(-) delete mode 100644 main.sy delete mode 100644 other.sy delete mode 100644 third.sy diff --git a/main.sy b/main.sy deleted file mode 100644 index 2e21a69..0000000 --- a/main.sy +++ /dev/null @@ -1,13 +0,0 @@ -use other -use third - -start :: fn { - other.f() - print other.g() - 42 <=> other.g() - other.g() <=> 42 - - other.third.print_the_third() - third.print_the_third() - third.main.other.third.main.third.print_the_third() -} diff --git a/other.sy b/other.sy deleted file mode 100644 index cee7fde..0000000 --- a/other.sy +++ /dev/null @@ -1,11 +0,0 @@ -use third - -f :: fn { - print "f" -} - - -g :: fn -> int { - answer :: 42 - ret answer -} diff --git a/third.sy b/third.sy deleted file mode 100644 index 777dd6d..0000000 --- a/third.sy +++ /dev/null @@ -1,5 +0,0 @@ -use main - -print_the_third :: fn { - print "three" -} -- cgit v1.2.1 From f5390849792718cd7b5c709241225b59ea86ae03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Sun, 7 Mar 2021 15:21:28 +0100 Subject: constants in outer scope --- src/compiler.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index 9c8f830..116e3d2 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -1184,10 +1184,9 @@ impl Compiler { // Global let var = self.find_variable(name) .expect(&format!("Couldn't find constant '{}' during prepass.", name)); - assert!(var.mutable); + assert!(!var.mutable); self.expression(block); - add_op(self, block, Op::AssignLocal(var.slot)); self.stack_mut()[var.slot].active = true; } else { // Local -- cgit v1.2.1 From 923834f19bfea1fae768cc990b5094b52e7cd43d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Sun, 7 Mar 2021 15:23:59 +0100 Subject: add test for constants in outer block --- progs/tests/global_constants.sy | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 progs/tests/global_constants.sy diff --git a/progs/tests/global_constants.sy b/progs/tests/global_constants.sy new file mode 100644 index 0000000..7ee6ca5 --- /dev/null +++ b/progs/tests/global_constants.sy @@ -0,0 +1,17 @@ +// TODO(ed): Pure functions +fac :: fn n: int -> int { + if n < 1 { ret 1 } + ret n * fac! n - 1 +} + +a :: fac! 4 +b :: a + fac! 2 +c := b + 1 + +start :: fn { + a <=> 24 + b <=> 24 + 2 + c <=> 24 + 2 + 1 + c += 1 + c <=> 24 + 2 + 2 +} -- cgit v1.2.1 From bffbde3be34ce854e169ad2296f44416414fbc75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Sun, 7 Mar 2021 15:27:19 +0100 Subject: add failing tests --- progs/tests/global_collision.sy | 11 +++++++++++ progs/tests/global_constants_edgecase.sy | 11 +++++++++++ 2 files changed, 22 insertions(+) create mode 100644 progs/tests/global_collision.sy create mode 100644 progs/tests/global_constants_edgecase.sy diff --git a/progs/tests/global_collision.sy b/progs/tests/global_collision.sy new file mode 100644 index 0000000..8dba295 --- /dev/null +++ b/progs/tests/global_collision.sy @@ -0,0 +1,11 @@ +// TODO(ed): Pure functions +fac :: fn a: int -> int { + if a < 1 { ret 1 } + ret a * fac! a - 1 +} + +a :: fac! 4 + +start :: fn { + a <=> 24 +} diff --git a/progs/tests/global_constants_edgecase.sy b/progs/tests/global_constants_edgecase.sy new file mode 100644 index 0000000..8dba295 --- /dev/null +++ b/progs/tests/global_constants_edgecase.sy @@ -0,0 +1,11 @@ +// TODO(ed): Pure functions +fac :: fn a: int -> int { + if a < 1 { ret 1 } + ret a * fac! a - 1 +} + +a :: fac! 4 + +start :: fn { + a <=> 24 +} -- cgit v1.2.1 From 2a8f5574191a61d8ef39706a7ac92ba14ab457eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Sun, 7 Mar 2021 15:42:28 +0100 Subject: add buildscript to fix tests not being found --- build.rs | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 build.rs diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..bcfc238 --- /dev/null +++ b/build.rs @@ -0,0 +1,3 @@ +fn main() { + println!("cargo:rerun-if-changed=progs/") +} -- cgit v1.2.1 From 1d8ce1dcc22a3f14b032d8be3e8a88a8cdbb538c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Sun, 7 Mar 2021 15:49:01 +0100 Subject: remove double test --- progs/tests/global_constants_edgecase.sy | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 progs/tests/global_constants_edgecase.sy diff --git a/progs/tests/global_constants_edgecase.sy b/progs/tests/global_constants_edgecase.sy deleted file mode 100644 index 8dba295..0000000 --- a/progs/tests/global_constants_edgecase.sy +++ /dev/null @@ -1,11 +0,0 @@ -// TODO(ed): Pure functions -fac :: fn a: int -> int { - if a < 1 { ret 1 } - ret a * fac! a - 1 -} - -a :: fac! 4 - -start :: fn { - a <=> 24 -} -- cgit v1.2.1 From d96ca7b986573a98cefdb67026516fd014a93c71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Sun, 7 Mar 2021 16:07:36 +0100 Subject: fix parameters colliding with global variables --- progs/tests/global_collision.sy | 1 - src/compiler.rs | 10 ++++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/progs/tests/global_collision.sy b/progs/tests/global_collision.sy index 8dba295..6bce509 100644 --- a/progs/tests/global_collision.sy +++ b/progs/tests/global_collision.sy @@ -1,4 +1,3 @@ -// TODO(ed): Pure functions fac :: fn a: int -> int { if a < 1 { ret 1 } ret a * fac! a - 1 diff --git a/src/compiler.rs b/src/compiler.rs index 116e3d2..b5d05d6 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -1124,17 +1124,19 @@ impl Compiler { } fn define(&mut self, mut var: Variable) -> Result { - if let Some(var) = self.find_variable(&var.name) { - if var.scope == self.frame().scope { + let frame = self.frame(); + + if let Some(res) = frame.find_local(&var.name).or(frame.find_upvalue(&var.name)) { + if res.scope == frame.scope { error!(self, format!("Multiple definitions of '{}' in this block.", - var.name)); + res.name)); return Err(()); } } let slot = self.stack().len(); var.slot = slot; - var.scope = self.frame().scope; + var.scope = frame.scope; var.line = self.line(); self.stack_mut().push(var); Ok(slot) -- cgit v1.2.1 From bc547d051d8f0a214224cf19363b1265508e4448 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Sun, 7 Mar 2021 16:35:54 +0100 Subject: look for outermost variables correctly --- src/compiler.rs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index b5d05d6..d383d47 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -285,6 +285,17 @@ impl Frame { } } + fn find_outer(&self, name: &str) -> Option { + // Only really makes sense in the outermost frame + // where declaration order doesn't matter + for var in self.stack.iter().rev() { + if var.name == name { + return Some(var.clone()); + } + } + None + } + fn find_local(&self, name: &str) -> Option { for var in self.stack.iter().rev() { if var.name == name && var.active { @@ -1145,7 +1156,7 @@ impl Compiler { fn definition_statement(&mut self, name: &str, typ: Type, block: &mut Block) { if self.frames().len() <= 1 { // Global - let var = self.find_variable(name) + let var = self.frame().find_outer(name) .expect(&format!("Couldn't find variable '{}' during prepass.", name)); assert!(var.mutable); @@ -1184,7 +1195,7 @@ impl Compiler { if self.frames().len() <= 1 { // Global - let var = self.find_variable(name) + let var = self.frame().find_outer(name) .expect(&format!("Couldn't find constant '{}' during prepass.", name)); assert!(!var.mutable); @@ -1722,7 +1733,6 @@ impl Compiler { let is_mut = self.peek() == Token::Equal; let var = Variable::new(&name, is_mut, ty); let slot = self.define(var).unwrap(); - self.frame_mut().stack[slot].active = true; } else { error!(self, format!("Failed to parse type global '{}'.", name)); } @@ -1732,14 +1742,12 @@ impl Compiler { Some((Token::ColonColon, _)), ..) => { let var = Variable::new(name, false, Type::Unknown); let slot = self.define(var).unwrap(); - self.frame_mut().stack[slot].active = true; } (Some((Token::Identifier(name), _)), Some((Token::ColonEqual, _)), ..) => { let var = Variable::new(name, true, Type::Unknown); let slot = self.define(var).unwrap(); - self.frame_mut().stack[slot].active = true; } -- cgit v1.2.1 From 0ce37d50dc8aa5789321949b8c661c2070f71d83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Sun, 7 Mar 2021 16:38:22 +0100 Subject: add tests for constants declaration order --- progs/tests/constants_declaration_order.sy | 6 ++++++ progs/tests/constants_declaration_order_wrong.sy | 8 ++++++++ 2 files changed, 14 insertions(+) create mode 100644 progs/tests/constants_declaration_order.sy create mode 100644 progs/tests/constants_declaration_order_wrong.sy diff --git a/progs/tests/constants_declaration_order.sy b/progs/tests/constants_declaration_order.sy new file mode 100644 index 0000000..93e6117 --- /dev/null +++ b/progs/tests/constants_declaration_order.sy @@ -0,0 +1,6 @@ +b :: 1 +a :: b + 1 + +start :: fn { + a <=> b + 1 +} diff --git a/progs/tests/constants_declaration_order_wrong.sy b/progs/tests/constants_declaration_order_wrong.sy new file mode 100644 index 0000000..37f5050 --- /dev/null +++ b/progs/tests/constants_declaration_order_wrong.sy @@ -0,0 +1,8 @@ +a :: b + 1 +b :: 1 + +start :: fn { + a <=> b + 1 +} + +// errors: [ErrorKind::SyntaxError(1, _)] -- cgit v1.2.1 From eab567c57dd41439ad4328a287baddda3e3270a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Sun, 7 Mar 2021 16:39:18 +0100 Subject: fix warnings --- src/compiler.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index d383d47..dc3bd96 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -1732,7 +1732,7 @@ impl Compiler { if let Ok(ty) = self.parse_type() { let is_mut = self.peek() == Token::Equal; let var = Variable::new(&name, is_mut, ty); - let slot = self.define(var).unwrap(); + let _ = self.define(var).unwrap(); } else { error!(self, format!("Failed to parse type global '{}'.", name)); } @@ -1741,13 +1741,13 @@ impl Compiler { (Some((Token::Identifier(name), _)), Some((Token::ColonColon, _)), ..) => { let var = Variable::new(name, false, Type::Unknown); - let slot = self.define(var).unwrap(); + let _ = self.define(var).unwrap(); } (Some((Token::Identifier(name), _)), Some((Token::ColonEqual, _)), ..) => { let var = Variable::new(name, true, Type::Unknown); - let slot = self.define(var).unwrap(); + let _ = self.define(var).unwrap(); } -- cgit v1.2.1