From 85d9b613dd3d66e9fe23115fb9b5c1246a54d4f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Sat, 30 Jan 2021 17:08:25 +0100 Subject: move things about --- src/compiler.rs | 113 +------------- src/error.rs | 5 +- src/lib.rs | 388 +++++++++++++++++++++++++++++++++++++++++++++++- src/main.rs | 8 +- src/vm.rs | 271 +-------------------------------- tihdy_derive/src/lib.rs | 8 +- 6 files changed, 401 insertions(+), 392 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index 648989d..722b944 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -1,12 +1,12 @@ use std::{borrow::Cow, path::{Path, PathBuf}}; -use std::rc::Rc; use std::cell::RefCell; -use std::collections::HashMap; use std::collections::hash_map::Entry; +use std::collections::HashMap; +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::vm::{Value, Block, Op}; macro_rules! nextable_enum { ( $name:ident { $( $thing:ident ),* $( , )? } ) => { @@ -49,84 +49,6 @@ nextable_enum!(Prec { Factor, }); - -#[derive(Clone)] -pub struct Prog { - pub blocks: Vec>>, - pub blobs: Vec>, - pub functions: Vec, -} - -#[derive(Debug, Clone)] -pub enum Type { - Void, - UnknownType, - Int, - Float, - Bool, - String, - Function(Vec, Box), - Blob(usize), - BlobInstance(usize), -} - -impl PartialEq for Type { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (Type::Void, Type::Void) => true, - (Type::BlobInstance(a), Type::BlobInstance(b)) => a == b, - (Type::Blob(a), Type::Blob(b)) => a == b, - (Type::Int, Type::Int) => true, - (Type::Float, Type::Float) => true, - (Type::Bool, Type::Bool) => true, - (Type::String, Type::String) => true, - (Type::Function(a_args, a_ret), Type::Function(b_args, b_ret)) => - a_args == b_args && a_ret == b_ret, - _ => false, - } - } -} - -impl From<&Value> for Type { - fn from(value: &Value) -> Type { - match value { - Value::BlobInstance(i, _) => Type::BlobInstance(*i), - Value::Blob(i) => Type::Blob(*i), - Value::Int(_) => Type::Int, - Value::Float(_) => Type::Float, - Value::Bool(_) => Type::Bool, - Value::String(_) => Type::String, - Value::Function(_, block) => block.borrow().ty.clone(), - _ => Type::Void, - } - } -} - -impl Type { - pub fn is_unkown(&self) -> bool { - match self { - Type::UnknownType => true, - _ => false, - } - } - - pub fn as_value(&self) -> Value { - match self { - Type::Void => Value::Nil, - Type::Blob(i) => Value::Blob(*i), - Type::BlobInstance(i) => Value::BlobInstance(*i, Rc::new(RefCell::new(Vec::new()))), - Type::UnknownType => Value::Unkown, - Type::Int => Value::Int(1), - Type::Float => Value::Float(1.0), - Type::Bool => Value::Bool(true), - Type::String => Value::String(Rc::new("".to_string())), - Type::Function(_, _) => Value::Function( - Vec::new(), - Rc::new(RefCell::new(Block::from_type(self)))), - } - } -} - #[derive(Clone)] struct Variable { name: String, @@ -182,35 +104,6 @@ impl Frame { } } -pub type RustFunction = fn(&[Value], bool) -> Result; - -#[derive(Debug, Clone)] -pub struct Blob { - pub name: String, - - pub name_to_field: HashMap, -} - -impl Blob { - pub fn new(name: &str) -> Self { - Self { - name: String::from(name), - name_to_field: 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(()) - } - } -} - struct Compiler { curr: usize, tokens: TokenStream, diff --git a/src/error.rs b/src/error.rs index b489cd1..2caced9 100644 --- a/src/error.rs +++ b/src/error.rs @@ -2,11 +2,12 @@ use std::fmt; use std::fs::File; use std::io::{self, BufRead}; use std::path::PathBuf; + use owo_colors::OwoColorize; -use crate::compiler::Type; +use crate::{Op, Value}; +use crate::Type; use crate::tokenizer::Token; -use crate::vm::{Op, Value}; #[derive(Debug, Clone)] pub enum ErrorKind { diff --git a/src/lib.rs b/src/lib.rs index 17f680c..bdd4ae4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,14 +1,22 @@ -use std::path::Path; +use std::cell::RefCell; +use std::collections::HashMap; +use std::collections::hash_map::Entry; +use std::fmt::Debug; +use std::path::{Path, PathBuf}; +use std::rc::Rc; + +use owo_colors::OwoColorize; + +use error::Error; +use tokenizer::TokenStream; + +use crate::error::ErrorKind; pub mod compiler; pub mod error; pub mod tokenizer; pub mod vm; -use compiler::RustFunction; -use error::Error; -use tokenizer::TokenStream; - pub fn run_file(path: &Path, print: bool, functions: Vec<(String, RustFunction)>) -> Result<(), Vec> { run(tokenizer::file_to_tokens(path), path, print, functions) } @@ -34,9 +42,12 @@ pub fn run(tokens: TokenStream, path: &Path, print: bool, functions: Vec<(String #[cfg(test)] mod tests { - use super::{run_file, run_string}; use std::path::Path; + use crate::error::ErrorKind; + + use super::{run_file, run_string}; + #[macro_export] macro_rules! assert_errs { ($result:expr, [ $( $kind:pat ),* ]) => { @@ -81,8 +92,6 @@ mod tests { }; } - use crate::error::ErrorKind; - #[test] fn unreachable_token() { assert_errs!(run_string("\n", true, Vec::new()), [ErrorKind::Unreachable]); @@ -300,3 +309,366 @@ a() <=> 4 test_file!(scoping, "tests/scoping.tdy"); test_file!(for_, "tests/for.tdy"); } + +#[derive(Clone)] +pub enum Value { + Blob(usize), + BlobInstance(usize, Rc>>), + Float(f64), + Int(i64), + Bool(bool), + String(Rc), + Function(Vec>>, Rc>), + ExternFunction(usize), + Unkown, + Nil, +} + +#[derive(Clone, Debug)] +pub struct UpValue { + slot: usize, + value: Value, +} + +impl UpValue { + fn new(value: usize) -> Self { + Self { + slot: value, + value: Value::Nil, + } + } + + fn get(&self, stack: &[Value]) -> Value { + if self.is_closed() { + self.value.clone() + } else { + stack[self.slot].clone() + } + } + + fn set(&mut self, stack: &mut [Value], value: Value) { + if self.is_closed() { + self.value = value; + } else { + stack[self.slot] = value; + } + } + + + fn is_closed(&self) -> bool { + self.slot == 0 + } + + fn close(&mut self, value: Value) { + self.slot = 0; + self.value = value; + } +} + +impl Debug for Value { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Value::Blob(i) => write!(fmt, "(blob {})", i), + Value::BlobInstance(i, v) => write!(fmt, "(inst {} {:?})", i, v), + Value::Float(f) => write!(fmt, "(float {})", f), + Value::Int(i) => write!(fmt, "(int {})", i), + Value::Bool(b) => write!(fmt, "(bool {})", b), + 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::Nil => write!(fmt, "(nil)"), + } + } +} + +impl Value { + fn identity(self) -> Self { + match self { + Value::Float(_) => Value::Float(1.0), + Value::Int(_) => Value::Int(1), + Value::Bool(_) => Value::Bool(true), + a => a, + } + } + + fn as_type(&self) -> Type { + match self { + Value::BlobInstance(i, _) => Type::BlobInstance(*i), + Value::Blob(i) => Type::Blob(*i), + Value::Float(_) => Type::Float, + Value::Int(_) => Type::Int, + Value::Bool(_) => Type::Bool, + Value::String(_) => Type::String, + Value::Function(_, block) => block.borrow().ty.clone(), + Value::ExternFunction(_) => Type::Void, //TODO + Value::Unkown => Type::UnknownType, + Value::Nil => Type::Void, + } + } +} + +#[derive(Debug, Clone)] +pub enum Op { + Illegal, + + Pop, + PopUpvalue, + Constant(Value), + + Get(String), + Set(String), + + Add, + Sub, + Mul, + Div, + Neg, + + And, + Or, + Not, + + Jmp(usize), + JmpFalse(usize), + + Equal, // == + Less, // < + Greater, // > + + Assert, + Unreachable, + + ReadLocal(usize), + AssignLocal(usize), + + ReadUpvalue(usize), + AssignUpvalue(usize), + + Define(Type), + + Call(usize), + + Print, + Return, +} + +#[derive(Debug)] +pub struct Block { + pub ty: Type, + pub ups: 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, +} + +impl Block { + pub fn new(name: &str, file: &Path, line: usize) -> Self { + Self { + ty: Type::Void, + ups: Vec::new(), + name: String::from(name), + file: file.to_owned(), + ops: Vec::new(), + last_line_offset: 0, + line_offsets: HashMap::new(), + line, + } + } + + pub fn from_type(ty: &Type) -> Self { + let mut block = Block::new("/empty/", Path::new(""), 0); + block.ty = ty.clone(); + block + } + + pub fn args(&self) -> &Vec { + if let Type::Function(ref args, _) = self.ty { + args + } else { + unreachable!() + } + } + + pub fn ret(&self) -> &Type { + if let Type::Function(_, ref ret) = self.ty { + ret + } else { + unreachable!() + } + } + + pub fn id(&self) -> (PathBuf, usize) { + (self.file.clone(), self.line) + } + + pub fn last_op(&self) -> Option<&Op> { + self.ops.last() + } + + pub 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 { + for i in (0..=ip).rev() { + if let Some(line) = self.line_offsets.get(&i) { + return *line; + } + } + return 0; + } + + pub fn debug_print(&self) { + println!(" === {} ===", self.name.blue()); + for (i, s) in self.ops.iter().enumerate() { + if self.line_offsets.contains_key(&i) { + print!("{:5} ", self.line_offsets[&i].red()); + } else { + print!(" {} ", "|".red()); + } + println!("{:05} {:?}", i.blue(), s); + } + println!(""); + } + + pub fn last_instruction(&mut self) -> &Op { + self.ops.last().unwrap() + } + + pub 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 { + let len = self.curr(); + self.add_line(token_position); + self.ops.extend_from_slice(ops); + len + } + + pub fn curr(&self) -> usize { + self.ops.len() + } + + pub fn patch(&mut self, op: Op, pos: usize) { + self.ops[pos] = op; + } +} + + +#[derive(Clone)] +pub struct Prog { + pub blocks: Vec>>, + pub blobs: Vec>, + pub functions: Vec, +} + +#[derive(Debug, Clone)] +pub enum Type { + Void, + UnknownType, + Int, + Float, + Bool, + String, + Function(Vec, Box), + Blob(usize), + BlobInstance(usize), +} + +impl PartialEq for Type { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Type::Void, Type::Void) => true, + (Type::BlobInstance(a), Type::BlobInstance(b)) => a == b, + (Type::Blob(a), Type::Blob(b)) => a == b, + (Type::Int, Type::Int) => true, + (Type::Float, Type::Float) => true, + (Type::Bool, Type::Bool) => true, + (Type::String, Type::String) => true, + (Type::Function(a_args, a_ret), Type::Function(b_args, b_ret)) => + a_args == b_args && a_ret == b_ret, + _ => false, + } + } +} + +impl From<&Value> for Type { + fn from(value: &Value) -> Type { + match value { + Value::BlobInstance(i, _) => Type::BlobInstance(*i), + Value::Blob(i) => Type::Blob(*i), + Value::Int(_) => Type::Int, + Value::Float(_) => Type::Float, + Value::Bool(_) => Type::Bool, + Value::String(_) => Type::String, + Value::Function(_, block) => block.borrow().ty.clone(), + _ => Type::Void, + } + } +} + +impl Type { + pub fn is_unkown(&self) -> bool { + match self { + Type::UnknownType => true, + _ => false, + } + } + + pub fn as_value(&self) -> Value { + match self { + Type::Void => Value::Nil, + Type::Blob(i) => Value::Blob(*i), + Type::BlobInstance(i) => Value::BlobInstance(*i, Rc::new(RefCell::new(Vec::new()))), + Type::UnknownType => Value::Unkown, + Type::Int => Value::Int(1), + Type::Float => Value::Float(1.0), + Type::Bool => Value::Bool(true), + Type::String => Value::String(Rc::new("".to_string())), + Type::Function(_, _) => Value::Function( + Vec::new(), + Rc::new(RefCell::new(Block::from_type(self)))), + } + } +} + +pub type RustFunction = fn(&[Value], bool) -> Result; + +#[derive(Debug, Clone)] +pub struct Blob { + pub name: String, + + pub name_to_field: HashMap, +} + +impl Blob { + pub fn new(name: &str) -> Self { + Self { + name: String::from(name), + name_to_field: 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(()) + } + } +} diff --git a/src/main.rs b/src/main.rs index 10b88ba..c52acc8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -41,10 +41,10 @@ fn parse_args() -> Args { tihdy_derive::extern_function!( extern_test - [tihdy::vm::Value::Float(x), tihdy::vm::Value::Float(y)] -> tihdy::vm::Type::Float => { - Ok(tihdy::vm::Value::Float(x + y)) + [tihdy::Value::Float(x), tihdy::Value::Float(y)] -> tihdy::Type::Float => { + Ok(tihdy::Value::Float(x + y)) }, - [tihdy::vm::Value::Float(x)] -> tihdy::vm::Type::Float => { - Ok(tihdy::vm::Value::Float(*x)) + [tihdy::Value::Float(x)] -> tihdy::Type::Float => { + Ok(tihdy::Value::Float(*x)) }, ); diff --git a/src/vm.rs b/src/vm.rs index 6ff2cf3..849aaa1 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -1,16 +1,15 @@ -use owo_colors::OwoColorize; -use std::collections::HashMap; +use std::cell::RefCell; use std::collections::hash_map::Entry; +use std::collections::HashMap; use std::fmt::Debug; -use std::path::{Path, PathBuf}; use std::rc::Rc; -use std::cell::RefCell; -pub use crate::compiler::Type; +use owo_colors::OwoColorize; -use crate::compiler::RustFunction; +use crate::{Blob, Block, Op, Prog, UpValue, Value}; use crate::error::{Error, ErrorKind}; -use crate::compiler::{Prog, Blob}; +use crate::RustFunction; +pub use crate::Type; macro_rules! error { ( $thing:expr, $kind:expr) => { @@ -21,262 +20,6 @@ macro_rules! error { }; } -#[derive(Clone)] -pub enum Value { - Blob(usize), - BlobInstance(usize, Rc>>), - Float(f64), - Int(i64), - Bool(bool), - String(Rc), - Function(Vec>>, Rc>), - ExternFunction(usize), - Unkown, - Nil, -} - -#[derive(Clone, Debug)] -pub struct UpValue { - slot: usize, - value: Value, -} - -impl UpValue { - fn new(value: usize) -> Self { - Self { - slot: value, - value: Value::Nil, - } - } - - fn get(&self, stack: &[Value]) -> Value { - if self.is_closed() { - self.value.clone() - } else { - stack[self.slot].clone() - } - } - - fn set(&mut self, stack: &mut [Value], value: Value) { - if self.is_closed() { - self.value = value; - } else { - stack[self.slot] = value; - } - } - - - fn is_closed(&self) -> bool { - self.slot == 0 - } - - fn close(&mut self, value: Value) { - self.slot = 0; - self.value = value; - } -} - -impl Debug for Value { - fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Value::Blob(i) => write!(fmt, "(blob {})", i), - Value::BlobInstance(i, v) => write!(fmt, "(inst {} {:?})", i, v), - Value::Float(f) => write!(fmt, "(float {})", f), - Value::Int(i) => write!(fmt, "(int {})", i), - Value::Bool(b) => write!(fmt, "(bool {})", b), - 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::Nil => write!(fmt, "(nil)"), - } - } -} - -impl Value { - fn identity(self) -> Self { - match self { - Value::Float(_) => Value::Float(1.0), - Value::Int(_) => Value::Int(1), - Value::Bool(_) => Value::Bool(true), - a => a, - } - } - - fn as_type(&self) -> Type { - match self { - Value::BlobInstance(i, _) => Type::BlobInstance(*i), - Value::Blob(i) => Type::Blob(*i), - Value::Float(_) => Type::Float, - Value::Int(_) => Type::Int, - Value::Bool(_) => Type::Bool, - Value::String(_) => Type::String, - Value::Function(_, block) => block.borrow().ty.clone(), - Value::ExternFunction(_) => Type::Void, //TODO - Value::Unkown => Type::UnknownType, - Value::Nil => Type::Void, - } - } -} - -#[derive(Debug, Clone)] -pub enum Op { - Illegal, - - Pop, - PopUpvalue, - Constant(Value), - - Get(String), - Set(String), - - Add, - Sub, - Mul, - Div, - Neg, - - And, - Or, - Not, - - Jmp(usize), - JmpFalse(usize), - - Equal, // == - Less, // < - Greater, // > - - Assert, - Unreachable, - - ReadLocal(usize), - AssignLocal(usize), - - ReadUpvalue(usize), - AssignUpvalue(usize), - - Define(Type), - - Call(usize), - - Print, - Return, -} - -#[derive(Debug)] -pub struct Block { - pub ty: Type, - pub ups: 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, -} - -impl Block { - pub fn new(name: &str, file: &Path, line: usize) -> Self { - Self { - ty: Type::Void, - ups: Vec::new(), - name: String::from(name), - file: file.to_owned(), - ops: Vec::new(), - last_line_offset: 0, - line_offsets: HashMap::new(), - line, - } - } - - pub fn from_type(ty: &Type) -> Self { - let mut block = Block::new("/empty/", Path::new(""), 0); - block.ty = ty.clone(); - block - } - - pub fn args(&self) -> &Vec { - if let Type::Function(ref args, _) = self.ty { - args - } else { - unreachable!() - } - } - - pub fn ret(&self) -> &Type { - if let Type::Function(_, ref ret) = self.ty { - ret - } else { - unreachable!() - } - } - - pub fn id(&self) -> (PathBuf, usize) { - (self.file.clone(), self.line) - } - - pub fn last_op(&self) -> Option<&Op> { - self.ops.last() - } - - pub 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 { - for i in (0..=ip).rev() { - if let Some(line) = self.line_offsets.get(&i) { - return *line; - } - } - return 0; - } - - pub fn debug_print(&self) { - println!(" === {} ===", self.name.blue()); - for (i, s) in self.ops.iter().enumerate() { - if self.line_offsets.contains_key(&i) { - print!("{:5} ", self.line_offsets[&i].red()); - } else { - print!(" {} ", "|".red()); - } - println!("{:05} {:?}", i.blue(), s); - } - println!(""); - } - - pub fn last_instruction(&mut self) -> &Op { - self.ops.last().unwrap() - } - - pub 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 { - let len = self.curr(); - self.add_line(token_position); - self.ops.extend_from_slice(ops); - len - } - - pub fn curr(&self) -> usize { - self.ops.len() - } - - pub fn patch(&mut self, op: Op, pos: usize) { - self.ops[pos] = op; - } -} - #[derive(Debug)] struct Frame { stack_offset: usize, @@ -973,8 +716,8 @@ impl VM { #[cfg(test)] mod tests { mod typing { - use crate::test_string; use crate::error::ErrorKind; + use crate::test_string; test_string!(uncallable_type, " f := fn i: int { diff --git a/tihdy_derive/src/lib.rs b/tihdy_derive/src/lib.rs index 7950d20..c0806ab 100644 --- a/tihdy_derive/src/lib.rs +++ b/tihdy_derive/src/lib.rs @@ -65,20 +65,20 @@ pub fn extern_function(tokens: TokenStream) -> TokenStream { let tokens = quote! { pub fn #function ( - __values: &[tihdy::vm::Value], + __values: &[tihdy::Value], __typecheck: bool - ) -> ::std::result::Result + ) -> ::std::result::Result { if __typecheck { #[allow(unused_variables)] match __values { #(#typecheck_blocks),* - _ => Err(tihdy::error::ErrorKind::ExternTypeMismatch(stringify!(#function).to_string(), __values.iter().map(|v| tihdy::vm::Type::from(v)).collect())) + _ => Err(tihdy::error::ErrorKind::ExternTypeMismatch(stringify!(#function).to_string(), __values.iter().map(|v| tihdy::Type::from(v)).collect())) } } else { match __values { #(#eval_blocks),* - _ => Err(tihdy::error::ErrorKind::ExternTypeMismatch(stringify!(#function).to_string(), __values.iter().map(|v| tihdy::vm::Type::from(v)).collect())) + _ => Err(tihdy::error::ErrorKind::ExternTypeMismatch(stringify!(#function).to_string(), __values.iter().map(|v| tihdy::Type::from(v)).collect())) } } } -- cgit v1.2.1