fix performance issue by using reference counting for objects
This commit is contained in:
@@ -5,6 +5,8 @@ use std::collections::HashMap;
|
|||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum RuntimeError {
|
pub enum RuntimeError {
|
||||||
@@ -49,15 +51,15 @@ where
|
|||||||
I: Iterator<Item = Result<ParseTree, ParseError>>
|
I: Iterator<Item = Result<ParseTree, ParseError>>
|
||||||
{
|
{
|
||||||
exprs: &'a mut I,
|
exprs: &'a mut I,
|
||||||
globals: &'a mut HashMap<String, Object>,
|
globals: &'a mut HashMap<String, Rc<RefCell<Object>>>,
|
||||||
locals: HashMap<String, Object>,
|
locals: HashMap<String, Rc<RefCell<Object>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, I> Executor<'a, I>
|
impl<'a, I> Executor<'a, I>
|
||||||
where
|
where
|
||||||
I: Iterator<Item = Result<ParseTree, ParseError>>,
|
I: Iterator<Item = Result<ParseTree, ParseError>>,
|
||||||
{
|
{
|
||||||
pub fn new(exprs: &'a mut I, globals: &'a mut HashMap<String, Object>) -> Self {
|
pub fn new(exprs: &'a mut I, globals: &'a mut HashMap<String, Rc<RefCell<Object>>>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
exprs,
|
exprs,
|
||||||
globals,
|
globals,
|
||||||
@@ -65,27 +67,27 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn _add_global(self, k: String, v: Object) -> Self {
|
pub fn _add_global(self, k: String, v: Rc<RefCell<Object>>) -> Self {
|
||||||
self.globals.insert(k, v);
|
self.globals.insert(k, v);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn locals(mut self, locals: HashMap<String, Object>) -> Self {
|
pub fn locals(mut self, locals: HashMap<String, Rc<RefCell<Object>>>) -> Self {
|
||||||
self.locals = locals;
|
self.locals = locals;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_local(mut self, k: String, v: Object) -> Self {
|
pub fn add_local(mut self, k: String, v: Rc<RefCell<Object>>) -> Self {
|
||||||
self.locals.insert(k, v);
|
self.locals.insert(k, v);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _get_object(&self, ident: &String) -> Result<&Object, RuntimeError> {
|
fn _get_object(&self, ident: &String) -> Result<&Rc<RefCell<Object>>, RuntimeError> {
|
||||||
self.locals.get(ident).or(self.globals.get(ident))
|
self.locals.get(ident).or(self.globals.get(ident))
|
||||||
.ok_or(RuntimeError::VariableUndefined(ident.clone()))
|
.ok_or(RuntimeError::VariableUndefined(ident.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_object_mut(&mut self, ident: &String) -> Result<&mut Object, RuntimeError> {
|
fn get_object_mut(&mut self, ident: &String) -> Result<&mut Rc<RefCell<Object>>, RuntimeError> {
|
||||||
self.locals.get_mut(ident).or(self.globals.get_mut(ident))
|
self.locals.get_mut(ident).or(self.globals.get_mut(ident))
|
||||||
.ok_or(RuntimeError::VariableUndefined(ident.clone()))
|
.ok_or(RuntimeError::VariableUndefined(ident.clone()))
|
||||||
}
|
}
|
||||||
@@ -236,7 +238,7 @@ where
|
|||||||
|
|
||||||
Executor::new(self.exprs, &mut self.globals)
|
Executor::new(self.exprs, &mut self.globals)
|
||||||
.locals(self.locals.clone())
|
.locals(self.locals.clone())
|
||||||
.add_local(ident, Object::value(value, g, self.locals.to_owned()))
|
.add_local(ident, Rc::new(RefCell::new(Object::value(value, g, self.locals.to_owned()))))
|
||||||
.exec(scope)
|
.exec(scope)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -247,7 +249,7 @@ where
|
|||||||
let g = self.globals.clone();
|
let g = self.globals.clone();
|
||||||
Executor::new(self.exprs, &mut self.globals)
|
Executor::new(self.exprs, &mut self.globals)
|
||||||
.locals(self.locals.clone())
|
.locals(self.locals.clone())
|
||||||
.add_local(ident, Object::variable(*body, g, self.locals.to_owned()))
|
.add_local(ident, Rc::new(RefCell::new(Object::variable(*body, g, self.locals.to_owned()))))
|
||||||
.exec(scope)
|
.exec(scope)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -255,7 +257,7 @@ where
|
|||||||
let g = self.globals.clone();
|
let g = self.globals.clone();
|
||||||
Executor::new(self.exprs, &mut self.globals)
|
Executor::new(self.exprs, &mut self.globals)
|
||||||
.locals(self.locals.clone())
|
.locals(self.locals.clone())
|
||||||
.add_local(func.name().unwrap().to_string(), Object::function(func, g, self.locals.clone()))
|
.add_local(func.name().unwrap().to_string(), Rc::new(RefCell::new(Object::function(func, g, self.locals.clone()))))
|
||||||
.exec(scope)
|
.exec(scope)
|
||||||
},
|
},
|
||||||
ParseTree::Compose(x, y) => {
|
ParseTree::Compose(x, y) => {
|
||||||
@@ -292,17 +294,17 @@ where
|
|||||||
ParseTree::FunctionCall(ident, args) => {
|
ParseTree::FunctionCall(ident, args) => {
|
||||||
let args = args.into_iter().map(|x| Object::variable(x, self.globals.clone(), self.locals.clone())).collect();
|
let args = args.into_iter().map(|x| Object::variable(x, self.globals.clone(), self.locals.clone())).collect();
|
||||||
let obj = self.get_object_mut(&ident)?;
|
let obj = self.get_object_mut(&ident)?;
|
||||||
let v = obj.eval()?;
|
let v = obj.borrow_mut().eval()?;
|
||||||
|
|
||||||
match v {
|
match v {
|
||||||
Value::Function(mut f) => f.call(obj.globals(), obj.locals(), args),
|
Value::Function(mut f) => f.call(obj.borrow().globals(), obj.borrow().locals(), args),
|
||||||
_ => Err(RuntimeError::FunctionUndefined(ident.clone()))
|
_ => Err(RuntimeError::FunctionUndefined(ident.clone()))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ParseTree::Variable(ident) => {
|
ParseTree::Variable(ident) => {
|
||||||
let obj = self.get_object_mut(&ident)?;
|
let obj = self.get_object_mut(&ident)?;
|
||||||
|
|
||||||
let v = obj.eval()?;
|
let v = obj.borrow_mut().eval()?;
|
||||||
|
|
||||||
Ok(v)
|
Ok(v)
|
||||||
},
|
},
|
||||||
@@ -350,7 +352,7 @@ where
|
|||||||
ParseTree::NonCall(name) => {
|
ParseTree::NonCall(name) => {
|
||||||
let obj = self.get_object_mut(&name)?;
|
let obj = self.get_object_mut(&name)?;
|
||||||
|
|
||||||
let v = obj.eval()?;
|
let v = obj.borrow_mut().eval()?;
|
||||||
|
|
||||||
Ok(v)
|
Ok(v)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
|
use std::cell::RefCell;
|
||||||
use crate::parser::ParseTree;
|
use crate::parser::ParseTree;
|
||||||
use crate::executor::{Executor, RuntimeError};
|
use crate::executor::{Executor, RuntimeError};
|
||||||
use crate::{Type, Object, Value};
|
use crate::{Type, Object, Value};
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt::{self, Display};
|
use std::fmt::{self, Display};
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct FunctionType(pub Box<Type>, pub Vec<Type>);
|
pub struct FunctionType(pub Box<Type>, pub Vec<Type>);
|
||||||
@@ -50,8 +52,8 @@ impl Function {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn call(&mut self,
|
pub(crate) fn call(&mut self,
|
||||||
mut globals: HashMap<String, Object>,
|
mut globals: HashMap<String, Rc<RefCell<Object>>>,
|
||||||
locals: HashMap<String, Object>,
|
locals: HashMap<String, Rc<RefCell<Object>>>,
|
||||||
args: Vec<Object>) -> Result<Value, RuntimeError>
|
args: Vec<Object>) -> Result<Value, RuntimeError>
|
||||||
{
|
{
|
||||||
let mut tree = vec![Ok(*self.body.clone())].into_iter();
|
let mut tree = vec![Ok(*self.body.clone())].into_iter();
|
||||||
@@ -61,11 +63,11 @@ impl Function {
|
|||||||
.locals(locals.clone());
|
.locals(locals.clone());
|
||||||
|
|
||||||
for (obj, name) in std::iter::zip(args.into_iter(), self.arg_names.clone().into_iter()) {
|
for (obj, name) in std::iter::zip(args.into_iter(), self.arg_names.clone().into_iter()) {
|
||||||
exec = exec.add_local(name.clone(), obj);
|
exec = exec.add_local(name.clone(), Rc::new(RefCell::new(obj)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(name) = self.name().map(|x| x.to_string()) {
|
if let Some(name) = self.name().map(|x| x.to_string()) {
|
||||||
exec = exec.add_local(name, Object::function(self.clone(), g, locals));
|
exec = exec.add_local(name, Rc::new(RefCell::new(Object::function(self.clone(), g, locals))));
|
||||||
}
|
}
|
||||||
|
|
||||||
exec.next().unwrap()
|
exec.next().unwrap()
|
||||||
|
|||||||
18
src/lib.rs
18
src/lib.rs
@@ -13,6 +13,8 @@ use std::fmt::Display;
|
|||||||
use std::io::BufRead;
|
use std::io::BufRead;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::iter::Peekable;
|
use std::iter::Peekable;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Type {
|
pub enum Type {
|
||||||
@@ -101,13 +103,13 @@ enum Cache {
|
|||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
struct Object {
|
struct Object {
|
||||||
locals: HashMap<String, Object>,
|
locals: HashMap<String, Rc<RefCell<Object>>>,
|
||||||
globals: HashMap<String, Object>,
|
globals: HashMap<String, Rc<RefCell<Object>>>,
|
||||||
value: Cache,
|
value: Cache,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Object {
|
impl Object {
|
||||||
pub fn variable(tree: ParseTree, globals: HashMap<String, Object>, locals: HashMap<String, Object>) -> Self {
|
pub fn variable(tree: ParseTree, globals: HashMap<String, Rc<RefCell<Object>>>, locals: HashMap<String, Rc<RefCell<Object>>>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
locals,
|
locals,
|
||||||
globals,
|
globals,
|
||||||
@@ -115,7 +117,7 @@ impl Object {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn value(v: Value, globals: HashMap<String, Object>, locals: HashMap<String, Object>) -> Self {
|
pub fn value(v: Value, globals: HashMap<String, Rc<RefCell<Object>>>, locals: HashMap<String, Rc<RefCell<Object>>>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
locals,
|
locals,
|
||||||
globals,
|
globals,
|
||||||
@@ -123,7 +125,7 @@ impl Object {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn function(func: Function, globals: HashMap<String, Object>, locals: HashMap<String, Object>) -> Self {
|
pub fn function(func: Function, globals: HashMap<String, Rc<RefCell<Object>>>, locals: HashMap<String, Rc<RefCell<Object>>>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
locals,
|
locals,
|
||||||
globals,
|
globals,
|
||||||
@@ -150,11 +152,11 @@ impl Object {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn locals(&self) -> HashMap<String, Object> {
|
pub fn locals(&self) -> HashMap<String, Rc<RefCell<Object>>> {
|
||||||
self.locals.clone()
|
self.locals.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn globals(&self) -> HashMap<String, Object> {
|
pub fn globals(&self) -> HashMap<String, Rc<RefCell<Object>>> {
|
||||||
self.globals.clone()
|
self.globals.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -162,7 +164,7 @@ impl Object {
|
|||||||
pub struct Runtime<'a, R: BufRead> {
|
pub struct Runtime<'a, R: BufRead> {
|
||||||
tokenizer: Peekable<Tokenizer<R>>,
|
tokenizer: Peekable<Tokenizer<R>>,
|
||||||
global_types: HashMap<String, Type>,
|
global_types: HashMap<String, Type>,
|
||||||
globals: HashMap<String, Object>,
|
globals: HashMap<String, Rc<RefCell<Object>>>,
|
||||||
parser: Option<Parser<'a, Tokenizer<R>>>,
|
parser: Option<Parser<'a, Tokenizer<R>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use crate::executor::Executor;
|
|||||||
use super::{Value, Type, Function, FunctionType};
|
use super::{Value, Type, Function, FunctionType};
|
||||||
use super::tokenizer::{Token, TokenizeError, Op};
|
use super::tokenizer::{Token, TokenizeError, Op};
|
||||||
|
|
||||||
use std::borrow::{BorrowMut, Cow};
|
use std::borrow::BorrowMut;
|
||||||
use std::error;
|
use std::error;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
@@ -106,7 +106,7 @@ pub(crate) struct Parser<'a, I: Iterator<Item = Result<Token, TokenizeError>>> {
|
|||||||
impl<'a, I: Iterator<Item = Result<Token, TokenizeError>>> Parser<'a, I> {
|
impl<'a, I: Iterator<Item = Result<Token, TokenizeError>>> Parser<'a, I> {
|
||||||
pub fn new(tokens: &'a mut Peekable<I>, globals: &'a mut HashMap<String, Type>) -> Self {
|
pub fn new(tokens: &'a mut Peekable<I>, globals: &'a mut HashMap<String, Type>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
tokens: tokens,
|
tokens,
|
||||||
globals,
|
globals,
|
||||||
locals: HashMap::new()
|
locals: HashMap::new()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user