From 636bd9f149a1df344933e1eaac39cc91ecdca706 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Fri, 5 Feb 2021 19:36:46 +0100 Subject: Assert -> AssertFailed --- src/error.rs | 4 ++-- src/vm.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/error.rs b/src/error.rs index e73d863..bbdd46b 100644 --- a/src/error.rs +++ b/src/error.rs @@ -17,7 +17,7 @@ pub enum ErrorKind { IndexOutOfBounds(Value, usize, usize), - Assert, + AssertFailed, InvalidProgram, Unreachable, @@ -53,7 +53,7 @@ impl fmt::Display for ErrorKind { .fold(String::new(), |a, v| { format!("{}{:?}, ", a, v) }); write!(f, "{} Cannot apply {:?} to values {}", "Runtime Type Error".bold(), op, values) } - ErrorKind::Assert => { + ErrorKind::AssertFailed => { write!(f, "{}", "Assertion failed".bold()) } ErrorKind::SyntaxError(line, token) => { diff --git a/src/vm.rs b/src/vm.rs index 474c51d..7f33821 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -306,7 +306,7 @@ impl VM { Op::Assert => { if matches!(self.pop(), Value::Bool(false)) { - error!(self, ErrorKind::Assert); + error!(self, ErrorKind::AssertFailed); } self.push(Value::Bool(true)); } -- cgit v1.2.1 From 826eb43254ddf8baadcd2ec1dacce594690526db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Fri, 5 Feb 2021 20:54:20 +0100 Subject: document public things and change some visibility and rename some variables and good commit yes thank --- src/compiler.rs | 20 ++++------ src/error.rs | 3 ++ src/lib.rs | 122 ++++++++++++++++++++++++++++---------------------------- src/vm.rs | 60 ++++++++++++---------------- 4 files changed, 97 insertions(+), 108 deletions(-) (limited to 'src') diff --git a/src/compiler.rs b/src/compiler.rs index 4988c4d..2caa4e9 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -103,7 +103,7 @@ impl Frame { } } -struct Compiler { +pub(crate) struct Compiler { curr: usize, tokens: TokenStream, current_file: PathBuf, @@ -130,7 +130,7 @@ macro_rules! push_frame { }); // Return value stored as a variable - $compiler.define_variable("", Type::UnknownType, &mut $block).unwrap(); + $compiler.define_variable("", Type::Unknown, &mut $block).unwrap(); $code $compiler.frames.pop().unwrap(); @@ -165,10 +165,8 @@ fn add_op(compiler: &Compiler, block: &mut Block, op: Op) -> usize { block.add(op, compiler.line()) } - - impl Compiler { - pub fn new(current_file: &Path, tokens: TokenStream) -> Self { + pub(crate) fn new(current_file: &Path, tokens: TokenStream) -> Self { Self { curr: 0, tokens, @@ -575,7 +573,7 @@ impl Compiler { self.scope(&mut function_block); for var in self.frame().upvalues.iter() { - function_block.ups.push((var.outer_slot, var.outer_upvalue, var.typ.clone())); + function_block.upvalues.push((var.outer_slot, var.outer_upvalue, var.typ.clone())); } }); @@ -775,7 +773,7 @@ impl Compiler { (Token::Identifier(name), Token::ColonEqual, ..) => { self.eat(); self.eat(); - self.definition_statement(&name, Type::UnknownType, block); + self.definition_statement(&name, Type::Unknown, block); } (Token::Comma, ..) => {} @@ -1028,7 +1026,7 @@ impl Compiler { (Token::Identifier(name), Token::ColonEqual, ..) => { self.eat(); self.eat(); - self.definition_statement(&name, Type::UnknownType, block); + self.definition_statement(&name, Type::Unknown, block); } (Token::Blob, Token::Identifier(_), ..) => { @@ -1068,7 +1066,7 @@ impl Compiler { } - pub fn compile(&mut self, name: &str, file: &Path, functions: &[(String, RustFunction)]) -> Result> { + pub(crate) fn compile(&mut self, name: &str, file: &Path, functions: &[(String, RustFunction)]) -> Result> { self.functions = functions .to_vec() .into_iter() @@ -1109,7 +1107,3 @@ impl Compiler { } } } - -pub fn compile(name: &str, file: &Path, tokens: TokenStream, functions: &[(String, RustFunction)]) -> Result> { - Compiler::new(file, tokens).compile(name, file, functions) -} diff --git a/src/error.rs b/src/error.rs index bbdd46b..deab89e 100644 --- a/src/error.rs +++ b/src/error.rs @@ -12,15 +12,18 @@ use crate::tokenizer::Token; #[derive(Debug, Clone)] pub enum ErrorKind { TypeError(Op, Vec), + /// (External function, parameters) ExternTypeMismatch(String, Vec), RuntimeTypeError(Op, Vec), + /// (Indexed value, length, index) IndexOutOfBounds(Value, usize, usize), AssertFailed, InvalidProgram, Unreachable, + /// (line, token) SyntaxError(usize, Token), } diff --git a/src/lib.rs b/src/lib.rs index 46bcb54..baaa846 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,23 +12,24 @@ use tokenizer::TokenStream; use crate::error::ErrorKind; -pub mod compiler; pub mod error; -pub mod tokenizer; pub mod vm; -pub fn run_file(path: &Path, print: bool, functions: Vec<(String, RustFunction)>) -> Result<(), Vec> { - run(tokenizer::file_to_tokens(path), path, print, functions) -} +mod compiler; +mod tokenizer; +/// Compiles a file and links the supplied functions as callable external +/// functions. Use this is 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::compile("main", path, tokens, &functions) { + match compiler::Compiler::new(path, tokens).compile("main", path, &functions) { Ok(prog) => { - let mut vm = vm::VM::new().print_blocks(print).print_ops(print); + let mut vm = vm::VM::new(); + vm.print_blocks = print; + vm.print_ops = print; vm.typecheck(&prog)?; vm.init(&prog); Ok(vm) @@ -37,14 +38,26 @@ pub fn compile_file(path: &Path, } } +/// Compiles and runs a file and links the supplied functions as 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) } -pub fn run(tokens: TokenStream, path: &Path, print: bool, functions: Vec<(String, RustFunction)>) -> Result<(), Vec> { - match compiler::compile("main", path, tokens, &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) { Ok(prog) => { - let mut vm = vm::VM::new().print_blocks(print).print_ops(print); + let mut vm = vm::VM::new(); + vm.print_blocks = print; + vm.print_ops = print; vm.typecheck(&prog)?; vm.init(&prog); if let Err(e) = vm.run() { @@ -57,12 +70,14 @@ pub fn run(tokens: TokenStream, path: &Path, print: bool, functions: Vec<(String } } +/// A linkable external function. Created either manually or using +/// [sylt_macro::extern_function]. pub type RustFunction = fn(&[Value], bool) -> Result; #[derive(Debug, Clone)] pub enum Type { Void, - UnknownType, + Unknown, Int, Float, Bool, @@ -117,15 +132,6 @@ impl From for Type { } } -impl Type { - pub fn is_unkown(&self) -> bool { - match self { - Type::UnknownType => true, - _ => false, - } - } -} - impl From<&Type> for Value { fn from(ty: &Type) -> Self { match ty { @@ -135,7 +141,7 @@ impl From<&Type> for Value { Type::Tuple(fields) => { Value::Tuple(Rc::new(fields.iter().map(Value::from).collect())) } - Type::UnknownType => Value::Unkown, + Type::Unknown => Value::Unknown, Type::Int => Value::Int(1), Type::Float => Value::Float(1.0), Type::Bool => Value::Bool(true), @@ -165,7 +171,7 @@ pub enum Value { String(Rc), Function(Vec>>, Rc>), ExternFunction(usize), - Unkown, + Unknown, Nil, } @@ -180,7 +186,7 @@ impl Debug for Value { Value::String(s) => write!(fmt, "(string \"{}\")", s), Value::Function(_, block) => write!(fmt, "(fn {}: {:?})", block.borrow().name, block.borrow().ty), Value::ExternFunction(slot) => write!(fmt, "(extern fn {})", slot), - Value::Unkown => write!(fmt, "(unkown)"), + Value::Unknown => write!(fmt, "(unknown)"), Value::Nil => write!(fmt, "(nil)"), Value::Tuple(v) => write!(fmt, "({:?})", v), } @@ -205,6 +211,7 @@ impl Value { } } +#[doc(hidden)] #[derive(Clone, Debug)] pub struct UpValue { slot: usize, @@ -249,26 +256,27 @@ impl UpValue { #[derive(Debug, Clone)] pub struct Blob { pub name: String, - - pub name_to_field: HashMap, + /// Maps field names to their slot and type. + pub fields: HashMap, } impl Blob { - pub fn new(name: &str) -> Self { + fn new(name: &str) -> Self { Self { name: String::from(name), - name_to_field: HashMap::new(), + fields: HashMap::new(), } } - pub fn add_field(&mut self, name: &str, ty: Type) -> Result<(), ()> { - let size = self.name_to_field.len(); - let entry = self.name_to_field.entry(String::from(name)); - if matches!(entry, Entry::Occupied(_)) { - Err(()) - } else { - entry.or_insert((size, ty)); - Ok(()) + fn add_field(&mut self, name: &str, ty: Type) -> Result<(), ()> { + let size = self.fields.len(); + let entry = self.fields.entry(String::from(name)); + match entry { + Entry::Occupied(_) => Err(()), + Entry::Vacant(v) => { + v.insert((size, ty)); + Ok(()) + } } } } @@ -333,8 +341,8 @@ mod op { pub fn neg(value: &Value) -> Value { match value { - Value::Float(a) => Value::Float(-a), - Value::Int(a) => Value::Int(-a), + Value::Float(a) => Value::Float(-*a), + Value::Int(a) => Value::Int(-*a), Value::Tuple(a) => Value::Tuple(Rc::new(a.iter().map(neg).collect())), _ => Value::Nil, } @@ -342,7 +350,7 @@ mod op { pub fn not(value: &Value) -> Value { match value { - Value::Bool(a) => Value::Bool(!a), + Value::Bool(a) => Value::Bool(!*a), Value::Tuple(a) => Value::Tuple(Rc::new(a.iter().map(not).collect())), _ => Value::Nil, } @@ -427,21 +435,21 @@ mod op { #[derive(Debug)] pub struct Block { pub ty: Type, - pub ups: Vec<(usize, bool, Type)>, + upvalues: Vec<(usize, bool, Type)>, pub name: String, pub file: PathBuf, - pub ops: Vec, - pub last_line_offset: usize, - pub line_offsets: HashMap, - pub line: usize, + ops: Vec, + last_line_offset: usize, + line_offsets: HashMap, + line: usize, } impl Block { - pub fn new(name: &str, file: &Path, line: usize) -> Self { + fn new(name: &str, file: &Path, line: usize) -> Self { Self { ty: Type::Void, - ups: Vec::new(), + upvalues: Vec::new(), name: String::from(name), file: file.to_owned(), ops: Vec::new(), @@ -451,7 +459,7 @@ impl Block { } } - pub fn empty_with_type(ty: &Type) -> Self { + fn empty_with_type(ty: &Type) -> Self { let mut block = Block::new("/empty/", Path::new(""), 0); block.ty = ty.clone(); block @@ -473,18 +481,14 @@ impl Block { } } - pub fn id(&self) -> (PathBuf, usize) { - (self.file.clone(), self.line) - } - - pub fn add_line(&mut self, token_position: usize) { + fn add_line(&mut self, token_position: usize) { if token_position != self.last_line_offset { self.line_offsets.insert(self.curr(), token_position); self.last_line_offset = token_position; } } - pub fn line(&self, ip: usize) -> usize { + fn line(&self, ip: usize) -> usize { for i in (0..=ip).rev() { if let Some(line) = self.line_offsets.get(&i) { return *line; @@ -503,32 +507,28 @@ impl Block { } println!("{:05} {:?}", i.blue(), s); } - println!(""); - } - - pub fn last_instruction(&mut self) -> &Op { - self.ops.last().unwrap() + println!(); } - pub fn add(&mut self, op: Op, token_position: usize) -> usize { + fn add(&mut self, op: Op, token_position: usize) -> usize { let len = self.curr(); self.add_line(token_position); self.ops.push(op); len } - pub fn add_from(&mut self, ops: &[Op], token_position: usize) -> usize { + fn add_from(&mut self, ops: &[Op], token_position: usize) -> usize { let len = self.curr(); self.add_line(token_position); self.ops.extend_from_slice(ops); len } - pub fn curr(&self) -> usize { + fn curr(&self) -> usize { self.ops.len() } - pub fn patch(&mut self, op: Op, pos: usize) { + fn patch(&mut self, op: Op, pos: usize) { self.ops[pos] = op; } } diff --git a/src/vm.rs b/src/vm.rs index 7f33821..5c42805 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -9,7 +9,7 @@ use owo_colors::OwoColorize; use crate::{Blob, Block, Op, Prog, UpValue, Value, op}; use crate::error::{Error, ErrorKind}; use crate::RustFunction; -pub use crate::Type; +use crate::Type; macro_rules! error { ( $thing:expr, $kind:expr) => { @@ -59,8 +59,8 @@ pub struct VM { blobs: Vec>, - print_blocks: bool, - print_ops: bool, + pub print_blocks: bool, + pub print_ops: bool, extern_functions: Vec, @@ -69,12 +69,15 @@ pub struct VM { #[derive(Eq, PartialEq)] pub enum OpResult { Yield, - Continue, Done, + + // Will never be returned. + #[doc(hidden)] + Continue, } impl VM { - pub fn new() -> Self { + pub(crate) fn new() -> Self { Self { upvalues: HashMap::new(), @@ -88,16 +91,6 @@ impl VM { } } - pub fn print_blocks(mut self, b: bool) -> Self { - self.print_blocks = b; - self - } - - pub fn print_ops(mut self, b: bool) -> Self { - self.print_ops = b; - self - } - fn drop_upvalue(&mut self, slot: usize, value: Value) { if let Entry::Occupied(entry) = self.upvalues.entry(slot) { entry.get().borrow_mut().close(value); @@ -210,7 +203,7 @@ impl VM { let value = match value { Value::Function(_, block) => { let mut ups = Vec::new(); - for (slot, is_up, _) in block.borrow().ups.iter() { + 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]) @@ -253,7 +246,7 @@ impl VM { Op::Get(field) => { let inst = self.pop(); if let Value::BlobInstance(ty, values) = inst { - let slot = self.blobs[ty].name_to_field.get(&field).unwrap().0; + let slot = self.blobs[ty].fields.get(&field).unwrap().0; self.push(values.borrow()[slot].clone()); } else { error!(self, ErrorKind::RuntimeTypeError(Op::Get(field.clone()), vec![inst])); @@ -263,7 +256,7 @@ impl VM { Op::Set(field) => { let (inst, value) = self.poppop(); if let Value::BlobInstance(ty, values) = inst { - let slot = self.blobs[ty].name_to_field.get(&field).unwrap().0; + let slot = self.blobs[ty].fields.get(&field).unwrap().0; values.borrow_mut()[slot] = value; } else { error!(self, ErrorKind::RuntimeTypeError(Op::Get(field.clone()), vec![inst])); @@ -350,7 +343,7 @@ impl VM { Value::Blob(blob_id) => { let blob = &self.blobs[blob_id]; - let mut values = Vec::with_capacity(blob.name_to_field.len()); + let mut values = Vec::with_capacity(blob.fields.len()); for _ in 0..values.capacity() { values.push(Value::Nil); } @@ -417,7 +410,7 @@ impl VM { Ok(OpResult::Continue) } - pub fn print_stack(&self) { + fn print_stack(&self) { let start = self.frame().stack_offset; print!(" {:3} [", start); for (i, s) in self.stack.iter().skip(start).enumerate() { @@ -434,7 +427,7 @@ impl VM { self.frame().block.borrow().ops[self.frame().ip]); } - pub fn init(&mut self, prog: &Prog) { + pub(crate) fn init(&mut self, prog: &Prog) { let block = Rc::clone(&prog.blocks[0]); self.blobs = prog.blobs.clone(); self.extern_functions = prog.functions.clone(); @@ -451,7 +444,6 @@ impl VM { } pub fn run(&mut self) -> Result { - if self.print_blocks { println!("\n [[{}]]\n", "RUNNING".red()); self.frame().block.borrow().debug_print(); @@ -483,7 +475,7 @@ impl VM { self.push(Value::Function(Vec::new(), block.clone())); let mut types = Vec::new(); - for (slot, is_up, ty) in block.borrow().ups.iter() { + for (slot, is_up, ty) in block.borrow().upvalues.iter() { if *is_up { types.push(ty.clone()); } else { @@ -492,11 +484,11 @@ impl VM { } let mut block_mut = block.borrow_mut(); - for (i, (_, is_up, ty)) in block_mut.ups.iter_mut().enumerate() { + for (i, (_, is_up, ty)) in block_mut.upvalues.iter_mut().enumerate() { if *is_up { continue; } let suggestion = &types[i]; - if ty.is_unkown() { + if matches!(ty, Type::Unknown) { *ty = suggestion.clone(); } else { if ty != suggestion { @@ -517,7 +509,7 @@ impl VM { Op::Get(field) => { let inst = self.pop(); if let Value::BlobInstance(ty, _) = inst { - let value = Value::from(&self.blobs[ty].name_to_field.get(&field).unwrap().1); + let value = Value::from(&self.blobs[ty].fields.get(&field).unwrap().1); self.push(value); } else { self.push(Value::Nil); @@ -530,7 +522,7 @@ impl VM { let inst = self.pop(); if let Value::BlobInstance(ty, _) = inst { - let ty = &self.blobs[ty].name_to_field.get(&field).unwrap().1; + let ty = &self.blobs[ty].fields.get(&field).unwrap().1; if ty != &Type::from(&value) { error!(self, ErrorKind::RuntimeTypeError(Op::Set(field.clone()), vec![inst])); } @@ -544,12 +536,12 @@ impl VM { } Op::ReadUpvalue(slot) => { - let value = Value::from(&self.frame().block.borrow().ups[slot].2); + let value = Value::from(&self.frame().block.borrow().upvalues[slot].2); self.push(value); } Op::AssignUpvalue(slot) => { - let var = self.frame().block.borrow().ups[slot].2.clone(); + let var = self.frame().block.borrow().upvalues[slot].2.clone(); let up = self.pop().into(); if var != up { error!(self, ErrorKind::TypeError(op, vec![var, up]), @@ -575,8 +567,8 @@ impl VM { Op::Define(ref ty) => { let top_type = self.stack.last().unwrap().into(); match (ty, top_type) { - (Type::UnknownType, top_type) - if top_type != Type::UnknownType => {} + (Type::Unknown, top_type) + if top_type != Type::Unknown => {} (a, b) if a != &b => { error!(self, ErrorKind::TypeError( @@ -595,12 +587,12 @@ impl VM { Value::Blob(blob_id) => { let blob = &self.blobs[blob_id]; - let mut values = Vec::with_capacity(blob.name_to_field.len()); + let mut values = Vec::with_capacity(blob.fields.len()); for _ in 0..values.capacity() { values.push(Value::Nil); } - for (slot, ty) in blob.name_to_field.values() { + for (slot, ty) in blob.fields.values() { values[*slot] = ty.into(); } @@ -710,7 +702,7 @@ impl VM { errors } - pub fn typecheck(&mut self, prog: &Prog) -> Result<(), Vec> { + pub(crate) fn typecheck(&mut self, prog: &Prog) -> Result<(), Vec> { let mut errors = Vec::new(); self.blobs = prog.blobs.clone(); -- cgit v1.2.1 From c43331a6e49c7fac5fcc5d61d6ff3d8d2221dbe0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Fri, 5 Feb 2021 21:02:04 +0100 Subject: code review --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index baaa846..bdafa03 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,7 +19,7 @@ mod compiler; mod tokenizer; /// Compiles a file and links the supplied functions as callable external -/// functions. Use this is you want your programs to be able to yield. +/// 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)> @@ -38,7 +38,7 @@ pub fn compile_file(path: &Path, } } -/// Compiles and runs a file and links the supplied functions as callable +/// 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> { -- cgit v1.2.1