From 519a9e5360f2cf0438dd09cfa3070bb9c8819f40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Mon, 15 Feb 2021 18:50:28 +0100 Subject: BlobInstance -> Instance --- src/compiler.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/compiler.rs') diff --git a/src/compiler.rs b/src/compiler.rs index f419527..e8607f7 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -1085,7 +1085,7 @@ impl Compiler { "float" => Ok(Type::Float), "bool" => Ok(Type::Bool), "str" => Ok(Type::String), - x => self.find_blob(x).map(|blob| Type::BlobInstance(blob)).ok_or(()), + x => self.find_blob(x).map(|blob| Type::Instance(blob)).ok_or(()), } } _ => Err(()), -- cgit v1.2.1 From f098c32e89626f75d83118d4d95d209299d28587 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Mon, 15 Feb 2021 19:18:25 +0100 Subject: change how blobs are stored --- src/compiler.rs | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) (limited to 'src/compiler.rs') diff --git a/src/compiler.rs b/src/compiler.rs index e8607f7..9a29d6d 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -228,11 +228,13 @@ pub(crate) struct Compiler { errors: Vec, blocks: Vec>>, - blobs: Vec, + blob_id: usize, functions: HashMap, constants: Vec, strings: Vec, + + } macro_rules! push_frame { @@ -290,7 +292,7 @@ impl Compiler { errors: vec![], blocks: Vec::new(), - blobs: Vec::new(), + blob_id: 0, functions: HashMap::new(), @@ -309,6 +311,12 @@ impl Compiler { }).unwrap() } + fn new_blob_id(&mut self) -> usize { + let id = self.blob_id; + self.blob_id += 1; + id + } + fn add_constant(&mut self, value: Value) -> usize { self.constants.push(value); self.constants.len() - 1 @@ -612,9 +620,10 @@ impl Compiler { } fn find_blob(&self, name: &str) -> Option { - self.blobs.iter().enumerate() - .find(|(_, x)| x.name == name) - .map(|(i, _)| i) + self.constants.iter().enumerate().find_map(|(i, x)| match x { + Value::Blob(b) if b.name == name => Some(i), + _ => None, + }) } fn call(&mut self, block: &mut Block) { @@ -805,8 +814,7 @@ impl Compiler { } } } else if let Some(blob) = self.find_blob(&name) { - let string = self.add_constant(Value::Blob(blob)); - add_op(self, block, Op::Constant(string)); + add_op(self, block, Op::Constant(blob)); parse_branch!(self, block, self.call(block)); } else if let Some(slot) = self.find_extern_function(&name) { let string = self.add_constant(Value::ExternFunction(slot)); @@ -1085,7 +1093,11 @@ impl Compiler { "float" => Ok(Type::Float), "bool" => Ok(Type::Bool), "str" => Ok(Type::String), - x => self.find_blob(x).map(|blob| Type::Instance(blob)).ok_or(()), + x => { + let blob = self.find_blob(x) + .unwrap_or_else(|| { error!(self, "Unkown blob."); 0 } ); + Ok(Type::from(&self.constants[blob])) + } } } _ => Err(()), @@ -1103,7 +1115,7 @@ impl Compiler { expect!(self, Token::LeftBrace, "Expected 'blob' body. AKA '{'."); - let mut blob = Blob::new(&name); + let mut blob = Blob::new(self.new_blob_id(), &name); loop { if matches!(self.peek(), Token::EOF | Token::RightBrace) { break; } if matches!(self.peek(), Token::Newline) { self.eat(); continue; } @@ -1131,7 +1143,7 @@ impl Compiler { expect!(self, Token::RightBrace, "Expected '}' after 'blob' body. AKA '}'."); - self.blobs.push(blob); + self.constants.push(Value::Blob(Rc::new(blob))); } fn blob_field(&mut self, block: &mut Block) { @@ -1341,7 +1353,6 @@ impl Compiler { if self.errors.is_empty() { Ok(Prog { blocks: self.blocks.clone(), - blobs: self.blobs.iter().map(|x| Rc::new(x.clone())).collect(), functions: functions.iter().map(|(_, f)| *f).collect(), constants: self.constants.clone(), strings: self.strings.clone(), -- cgit v1.2.1 From 4d2121c548492c591d3366f6a3b919b098c349d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Mon, 15 Feb 2021 22:23:11 +0100 Subject: allow usages of blobs before definition --- src/compiler.rs | 61 +++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 38 insertions(+), 23 deletions(-) (limited to 'src/compiler.rs') diff --git a/src/compiler.rs b/src/compiler.rs index 9a29d6d..95290a0 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -1,6 +1,6 @@ use std::{borrow::Cow, path::{Path, PathBuf}}; use std::cell::RefCell; -use std::collections::HashMap; +use std::collections::{HashMap, hash_map::Entry}; use std::rc::Rc; use crate::{Blob, Block, Op, Prog, RustFunction, Type, Value}; @@ -229,12 +229,11 @@ pub(crate) struct Compiler { blocks: Vec>>, blob_id: usize, + unkowns: HashMap, functions: HashMap, constants: Vec, strings: Vec, - - } macro_rules! push_frame { @@ -293,6 +292,7 @@ impl Compiler { blocks: Vec::new(), blob_id: 0, + unkowns: HashMap::new(), functions: HashMap::new(), @@ -619,11 +619,18 @@ impl Compiler { Self::find_and_capture_variable(name, self.frames.iter_mut().rev()) } - fn find_blob(&self, name: &str) -> Option { - self.constants.iter().enumerate().find_map(|(i, x)| match x { + fn find_blob(&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), _ => None, - }) + }); + if res.is_some() { + return res.unwrap(); + } + let constant = self.add_constant(Value::Nil); + let line = self.line(); + let entry = self.unkowns.entry(name.to_string()); + entry.or_insert((constant, line)).0 } fn call(&mut self, block: &mut Block) { @@ -680,9 +687,6 @@ impl Compiler { break; } } - if !self.panic { - println!("LINE {} -- ", self.line()); - } } _ => { @@ -788,6 +792,16 @@ impl Compiler { Token::Identifier(name) => name, _ => unreachable!(), }; + + // Global functions take precedence + if let Some(slot) = self.find_extern_function(&name) { + let string = self.add_constant(Value::ExternFunction(slot)); + add_op(self, block, Op::Constant(string)); + self.call(block); + return; + } + + // Variables if let Some(var) = self.find_variable(&name) { if var.upvalue { add_op(self, block, Op::ReadUpvalue(var.slot)); @@ -803,26 +817,22 @@ impl Compiler { add_op(self, block, Op::Get(string)); } else { error!(self, "Expected fieldname after '.'."); - break; + return; } } _ => { if !parse_branch!(self, block, self.call(block)) { - break + return; } } } } - } else if let Some(blob) = self.find_blob(&name) { - add_op(self, block, Op::Constant(blob)); - parse_branch!(self, block, self.call(block)); - } else if let Some(slot) = self.find_extern_function(&name) { - let string = self.add_constant(Value::ExternFunction(slot)); - add_op(self, block, Op::Constant(string)); - self.call(block); - } else { - error!(self, format!("Using undefined variable {}.", name)); } + + // Blobs - Always returns a blob since it's filled in if it isn't used. + let blob = self.find_blob(&name); + add_op(self, block, Op::Constant(blob)); + parse_branch!(self, block, self.call(block)); } fn define_variable(&mut self, name: &str, typ: Type, _block: &mut Block) -> Result { @@ -1094,8 +1104,7 @@ impl Compiler { "bool" => Ok(Type::Bool), "str" => Ok(Type::String), x => { - let blob = self.find_blob(x) - .unwrap_or_else(|| { error!(self, "Unkown blob."); 0 } ); + let blob = self.find_blob(x); Ok(Type::from(&self.constants[blob])) } } @@ -1143,7 +1152,13 @@ impl Compiler { expect!(self, Token::RightBrace, "Expected '}' after 'blob' body. AKA '}'."); - self.constants.push(Value::Blob(Rc::new(blob))); + let blob = Value::Blob(Rc::new(blob)); + if let Entry::Occupied(entry) = self.unkowns.entry(name) { + let (_, (slot, _)) = entry.remove_entry(); + self.constants[slot] = blob; + } else { + self.constants.push(blob); + } } fn blob_field(&mut self, block: &mut Block) { -- cgit v1.2.1 From 3c5a33f008b40e272d3a720aa81fb5a8568a4527 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Mon, 15 Feb 2021 22:33:17 +0100 Subject: give better error messages --- src/compiler.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'src/compiler.rs') diff --git a/src/compiler.rs b/src/compiler.rs index 95290a0..faca7f8 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -361,16 +361,21 @@ impl Compiler { } fn error(&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) { if self.panic { return } self.panic = true; self.errors.push(Error { kind, file: self.current_file.clone(), - line: self.line(), + line, message, }); } + fn peek(&self) -> Token { self.peek_at(0) } @@ -1363,6 +1368,18 @@ impl Compiler { add_op(self, &mut block, Op::Return); block.ty = Type::Function(Vec::new(), Box::new(Type::Void)); + if self.unkowns.len() != 0 { + let errors: Vec<_> = self.unkowns.iter().map(|(name, (_, line))| + (ErrorKind::SyntaxError(*line, Token::Identifier(name.clone())), + *line, + format!("Usage of undefined 'blob': '{}'.", name,) + )) + .collect(); + for (e, l, m) in errors.iter() { + self.error_on_line(e.clone(), *l, Some(m.clone())); + } + } + self.blocks.insert(0, Rc::new(RefCell::new(block))); if self.errors.is_empty() { -- cgit v1.2.1 From 2a8020706c6309ac23755839cfdb13cf4e11d303 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Mon, 15 Feb 2021 23:49:42 +0100 Subject: add magic blob inference --- src/compiler.rs | 45 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 9 deletions(-) (limited to 'src/compiler.rs') diff --git a/src/compiler.rs b/src/compiler.rs index faca7f8..ca571ee 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -573,7 +573,7 @@ impl Compiler { /// Entry point for all expression parsing. fn expression(&mut self, block: &mut Block) { match self.peek_four() { - (Token::Fn, ..) => self.function(block), + (Token::Fn, ..) => { self.function(block, None); }, _ => self.parse_precedence(block, Prec::No), } } @@ -624,9 +624,10 @@ impl Compiler { Self::find_and_capture_variable(name, self.frames.iter_mut().rev()) } - fn find_blob(&mut self, name: &str) -> usize { + 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 res.is_some() { @@ -703,11 +704,13 @@ impl Compiler { } // TODO(ed): de-complexify - fn function(&mut self, block: &mut Block) { + fn function(&mut self, block: &mut Block, name: Option<&str>) { expect!(self, Token::Fn, "Expected 'fn' at start of function."); let top = self.stack().len() - 1; - let name = if !self.stack()[top].active { + let name = if let Some(name) = name { + Cow::Owned(String::from(name)) + } else if !self.stack()[top].active { self.stack_mut()[top].active = true; Cow::Borrowed(&self.stack()[top].name) } else { @@ -787,8 +790,11 @@ impl Compiler { let function_block = Rc::new(RefCell::new(function_block)); - let constant = self.add_constant(Value::Function(Vec::new(), Rc::clone(&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)); self.blocks[block_id] = function_block; + let constant = self.add_constant(function); add_op(self, block, Op::Constant(constant)); } @@ -835,8 +841,8 @@ impl Compiler { } // Blobs - Always returns a blob since it's filled in if it isn't used. - let blob = self.find_blob(&name); - add_op(self, block, Op::Constant(blob)); + let con = self.find_constant(&name); + add_op(self, block, Op::Constant(con)); parse_branch!(self, block, self.call(block)); } @@ -902,6 +908,20 @@ 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(); + if let Entry::Occupied(entry) = self.unkowns.entry(String::from(name)) { + let (_, (slot, _)) = entry.remove_entry(); + self.constants[slot] = self.constants.pop().unwrap(); + } + return; + } + } + let slot = self.define_constant(name, typ.clone(), block); self.expression(block); @@ -1109,8 +1129,15 @@ impl Compiler { "bool" => Ok(Type::Bool), "str" => Ok(Type::String), x => { - let blob = self.find_blob(x); - Ok(Type::from(&self.constants[blob])) + let blob = self.find_constant(x); + if let Value::Blob(blob) = &self.constants[blob] { + Ok(Type::Instance(Rc::clone(blob))) + } else { + // TODO(ed): This is kinda bad. If the type cannot + // be found it tries to infer it during runtime + // and doesn't verify it. + Ok(Type::Unknown) + } } } } -- cgit v1.2.1 From 06cc26d9639102f4ab9b0eabbf1ece3f395798e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Mon, 15 Feb 2021 23:54:05 +0100 Subject: fix error message --- src/compiler.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/compiler.rs') diff --git a/src/compiler.rs b/src/compiler.rs index ca571ee..ec78118 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -1399,7 +1399,7 @@ impl Compiler { let errors: Vec<_> = self.unkowns.iter().map(|(name, (_, line))| (ErrorKind::SyntaxError(*line, Token::Identifier(name.clone())), *line, - format!("Usage of undefined 'blob': '{}'.", name,) + format!("Usage of undefined value: '{}'.", name,) )) .collect(); for (e, l, m) in errors.iter() { -- cgit v1.2.1 From e86b1be782c2c2f57e968557d7f91bbcc7b8b27f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Tue, 16 Feb 2021 21:10:03 +0100 Subject: fix the failing testcase --- src/compiler.rs | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/compiler.rs') diff --git a/src/compiler.rs b/src/compiler.rs index ec78118..361d93a 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -917,6 +917,9 @@ impl Compiler { if let Entry::Occupied(entry) = self.unkowns.entry(String::from(name)) { let (_, (slot, _)) = entry.remove_entry(); self.constants[slot] = self.constants.pop().unwrap(); + add_op(self, block, Op::Link(slot)); + } else { + add_op(self, block, Op::Link(self.constants.len() - 1)); } return; } -- cgit v1.2.1 From 6801bea82458ab50e6d81b3bb3f3aac7b2f93ed6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Tue, 16 Feb 2021 21:29:11 +0100 Subject: let some fix --- src/compiler.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/compiler.rs') diff --git a/src/compiler.rs b/src/compiler.rs index 361d93a..be99b01 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -630,8 +630,8 @@ impl Compiler { Value::Function(_, b) if b.borrow().name == name => Some(i), _ => None, }); - if res.is_some() { - return res.unwrap(); + if let Some(res) = res { + return res; } let constant = self.add_constant(Value::Nil); let line = self.line(); -- cgit v1.2.1 From 5836cac092821da390b4d754407125864b77288d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Tue, 16 Feb 2021 21:34:51 +0100 Subject: unkowns -> unknown --- src/compiler.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src/compiler.rs') diff --git a/src/compiler.rs b/src/compiler.rs index be99b01..94ae2aa 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -229,7 +229,7 @@ pub(crate) struct Compiler { blocks: Vec>>, blob_id: usize, - unkowns: HashMap, + unknown: HashMap, functions: HashMap, constants: Vec, @@ -292,7 +292,7 @@ impl Compiler { blocks: Vec::new(), blob_id: 0, - unkowns: HashMap::new(), + unknown: HashMap::new(), functions: HashMap::new(), @@ -635,7 +635,7 @@ impl Compiler { } let constant = self.add_constant(Value::Nil); let line = self.line(); - let entry = self.unkowns.entry(name.to_string()); + let entry = self.unknown.entry(name.to_string()); entry.or_insert((constant, line)).0 } @@ -914,7 +914,7 @@ impl Compiler { // Remove the function, since it's a constant and we already // added it. block.ops.pop().unwrap(); - if let Entry::Occupied(entry) = self.unkowns.entry(String::from(name)) { + if let Entry::Occupied(entry) = self.unknown.entry(String::from(name)) { let (_, (slot, _)) = entry.remove_entry(); self.constants[slot] = self.constants.pop().unwrap(); add_op(self, block, Op::Link(slot)); @@ -1188,7 +1188,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.unkowns.entry(name) { + if let Entry::Occupied(entry) = self.unknown.entry(name) { let (_, (slot, _)) = entry.remove_entry(); self.constants[slot] = blob; } else { @@ -1398,8 +1398,8 @@ impl Compiler { add_op(self, &mut block, Op::Return); block.ty = Type::Function(Vec::new(), Box::new(Type::Void)); - if self.unkowns.len() != 0 { - let errors: Vec<_> = self.unkowns.iter().map(|(name, (_, line))| + 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,) -- cgit v1.2.1