aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib.rs
diff options
context:
space:
mode:
authorGustav Sörnäs <gustav@sornas.net>2021-01-30 17:08:25 +0100
committerGustav Sörnäs <gustav@sornas.net>2021-01-30 17:08:38 +0100
commit85d9b613dd3d66e9fe23115fb9b5c1246a54d4f0 (patch)
tree116da6aa4c0280c66366eadce27d095b95ba6946 /src/lib.rs
parent03977fdf0d09156dbee222194d0800b4ba8dde8b (diff)
downloadsylt-85d9b613dd3d66e9fe23115fb9b5c1246a54d4f0.tar.gz
move things about
Diffstat (limited to 'src/lib.rs')
-rw-r--r--src/lib.rs388
1 files changed, 380 insertions, 8 deletions
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<Error>> {
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<RefCell<Vec<Value>>>),
+ Float(f64),
+ Int(i64),
+ Bool(bool),
+ String(Rc<String>),
+ Function(Vec<Rc<RefCell<UpValue>>>, Rc<RefCell<Block>>),
+ 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<Op>,
+ pub last_line_offset: usize,
+ pub line_offsets: HashMap<usize, usize>,
+ 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<Type> {
+ 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<Rc<RefCell<Block>>>,
+ pub blobs: Vec<Rc<Blob>>,
+ pub functions: Vec<RustFunction>,
+}
+
+#[derive(Debug, Clone)]
+pub enum Type {
+ Void,
+ UnknownType,
+ Int,
+ Float,
+ Bool,
+ String,
+ Function(Vec<Type>, Box<Type>),
+ 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<Value, ErrorKind>;
+
+#[derive(Debug, Clone)]
+pub struct Blob {
+ pub name: String,
+
+ pub name_to_field: HashMap<String, (usize, Type)>,
+}
+
+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(())
+ }
+ }
+}