new error handling!

This commit is contained in:
2024-10-27 22:01:20 -04:00
parent ca6b977220
commit c29f689252
7 changed files with 590 additions and 582 deletions

View File

@@ -2,17 +2,19 @@ mod tokenizer;
mod parser;
mod executor;
mod function;
mod error;
use executor::{Executor, RuntimeError};
use executor::Executor;
use parser::{ParseTree, Parser};
use tokenizer::Tokenizer;
use function::{FunctionType, Function};
use error::Error;
use core::str;
use std::collections::HashMap;
use std::fmt::Display;
use std::io::BufRead;
use std::fmt;
use std::iter::Peekable;
use std::sync::{Arc, Mutex};
#[derive(Clone, Debug)]
@@ -147,16 +149,15 @@ impl Object {
}
/// evaluate the tree inside an object if it isn't evaluated yet, returns the value
pub fn eval(&mut self) -> Result<Value, RuntimeError> {
pub fn eval(&mut self) -> Result<Value, Error> {
match self.value.clone() {
Cache::Cached(v) => Ok(v),
Cache::Uncached(tree) => {
let mut t = vec![Ok(tree.clone())].into_iter();
let mut exec = Executor::new(&mut t, &mut self.globals)
let mut exec = Executor::new()
.add_globals(self.globals.clone())
.locals(self.locals.clone());
let v = exec.exec(Box::new(tree))?;
let v = exec.exec(tree)?;
self.value = Cache::Cached(v.clone());
@@ -174,20 +175,111 @@ impl Object {
}
}
pub struct Runtime<'a, R: BufRead> {
tokenizer: Peekable<Tokenizer<R>>,
global_types: HashMap<String, Type>,
globals: HashMap<String, Arc<Mutex<Object>>>,
parser: Option<Parser<'a, Tokenizer<R>>>,
/// A custom type used in the tokenizer to automatically keep track of which character we are on
pub(crate) struct CodeIter<R: BufRead> {
reader: R,
code: String,
// position in code
pos: usize,
// the current line number
line: usize,
// column in the current line
column: usize,
}
impl<'a, R: BufRead> Runtime<'a, R> {
pub fn new(reader: R, name: &str) -> Self {
impl<R: BufRead> CodeIter<R> {
fn new(reader: R) -> Self {
Self {
tokenizer: Tokenizer::new(reader, name).peekable(),
reader,
code: String::new(),
pos: 0,
line: 0,
column: 0,
}
}
pub(crate) fn getpos(&self) -> (usize, usize) {
(self.line, self.column)
}
fn code(&self) -> String {
self.code.clone()
}
// Peekable is useless here because I cannot access the inner object otherwise
pub(crate) fn peek(&mut self) -> Option<char> {
if let Some(c) = self.code.chars().nth(self.pos) {
Some(c)
} else {
match self.reader.read_line(&mut self.code) {
Ok(0) => return None,
Ok(_) => (),
Err(_e) => panic!("aaaa"),
};
self.peek()
}
}
pub(crate) fn next_if(&mut self, func: impl FnOnce(&char) -> bool) -> Option<char> {
let c = self.peek()?;
if (func)(&c) {
self.next()
} else {
None
}
}
}
impl<R: BufRead> Iterator for CodeIter<R> {
type Item = char;
fn next(&mut self) -> Option<Self::Item> {
if let Some(c) = self.code.chars().nth(self.pos) {
match c {
'\n' => {
self.line += 1;
self.column = 0;
self.pos += 1;
None
},
c => {
self.column += 1;
self.pos += 1;
Some(c)
}
}
} else {
match self.reader.read_line(&mut self.code) {
Ok(0) => return None,
Ok(_) => (),
Err(_e) => panic!("aaaa"),
};
self.next()
}
}
}
pub struct Runtime<R: BufRead> {
reader: Arc<Mutex<CodeIter<R>>>,
filename: String,
global_types: HashMap<String, Type>,
globals: HashMap<String, Arc<Mutex<Object>>>,
}
impl<R: BufRead> Runtime<R> {
pub fn new(reader: R, filename: &str) -> Self {
Self {
reader: Arc::new(Mutex::new(CodeIter::new(reader))),
filename: filename.to_string(),
global_types: HashMap::new(),
globals: HashMap::new(),
parser: None,
}.add_global("version'", Value::String(
format!("{} ({}/{})",
env!("CARGO_PKG_VERSION"),
@@ -197,6 +289,12 @@ impl<'a, R: BufRead> Runtime<'a, R> {
))
}
pub fn code(&self) -> String {
let reader = self.reader.lock().unwrap();
let code = reader.code();
code
}
pub fn add_global(mut self, name: &str, value: Value) -> Self {
self.global_types.insert(name.to_string(), value.get_type());
self.globals.insert(name.to_string(),
@@ -207,9 +305,27 @@ impl<'a, R: BufRead> Runtime<'a, R> {
self
}
}
pub fn values(&'a mut self) -> impl Iterator<Item = Result<Value, RuntimeError>> + 'a {
self.parser = Some(Parser::new(&mut self.tokenizer, &mut self.global_types));
Executor::new(self.parser.as_mut().unwrap(), &mut self.globals)
impl<R: BufRead> Iterator for Runtime<R> {
type Item = Result<Value, Error>;
fn next(&mut self) -> Option<Self::Item> {
let tokenizer = Tokenizer::new(self.reader.clone());
let tree = Parser::new()
.add_globals(self.global_types.clone())
.parse(&mut tokenizer.peekable());
let tree = match tree.map_err(|e| e
.code(self.code())
.file(self.filename.clone()))
{
Ok(Some(tree)) => tree,
Ok(None) => return None,
Err(e) => return Some(Err(e))
};
Some(Executor::new().add_globals(self.globals.clone()).exec(tree))
}
}