updated a bunch of stuff

This commit is contained in:
Moritz Gmeiner 2024-09-01 19:16:30 +02:00
commit 67bb5fe8fd
24 changed files with 683 additions and 702 deletions

View file

@ -10,7 +10,7 @@ use crate::{LoxFunction, LoxReference, Value};
pub struct LoxClass {
superclass: Option<Rc<LoxClass>>,
name: String,
name: Box<str>,
methods: FxHashMap<String, Value>,
}
@ -18,7 +18,7 @@ pub struct LoxClass {
/// Representation of a class in Lox. Always behind an Rc to ensure uniqueness. Should never be handled raw.
impl LoxClass {
pub fn new(
name: impl Into<String>,
name: impl Into<Box<str>>,
methods: FxHashMap<String, Value>,
superclass: Option<Rc<LoxClass>>,
) -> Rc<Self> {
@ -33,10 +33,7 @@ impl LoxClass {
let mut body = init.body().clone();
if let Stmt::Block { ref mut statements } = body {
statements.push(Stmt::return_stmt(Expr::LocalVariable {
name: "this".to_owned(),
level: 1,
}));
statements.push(Stmt::return_stmt(Expr::local_variable("this", 1)));
} else {
panic!("Body of init method of class {name} wasn't a block");
}
@ -130,7 +127,12 @@ impl LoxClass {
impl Display for LoxClass {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "<class {} at {:#X}>", self.name, (self as *const LoxClass) as usize)
write!(
f,
"<class {} at {:#X}>",
self.name,
(self as *const LoxClass) as usize
)
}
}

View file

@ -8,12 +8,11 @@ use crate::error::RuntimeError;
use super::value::HeapedValue;
use super::{Runtime, Value};
pub type Scope = FxHashMap<String, HeapedValue>;
pub type Scope = FxHashMap<Box<str>, HeapedValue>;
#[derive(Debug)]
pub struct Environment<'a> {
scope_stack: Vec<Scope>,
scope_top: usize,
runtime: &'a mut Runtime,
@ -24,7 +23,6 @@ impl<'a> Environment<'a> {
pub fn new(runtime: &'a mut Runtime) -> Self {
Environment {
scope_stack: Vec::new(),
scope_top: 0,
runtime,
@ -32,6 +30,10 @@ impl<'a> Environment<'a> {
}
}
pub fn runtime(&mut self) -> &mut Runtime {
self.runtime
}
pub fn push_arg(&mut self, arg: Value) {
self.arg_stack.push(arg);
}
@ -44,16 +46,16 @@ impl<'a> Environment<'a> {
std::mem::take(&mut self.arg_stack)
}
pub fn globals(&self) -> &FxHashMap<String, Value> {
pub fn globals(&self) -> &FxHashMap<Box<str>, Value> {
self.runtime.globals()
}
pub fn scopes(&self) -> &[Scope] {
&self.scope_stack[..self.scope_top]
&self.scope_stack
}
pub fn scopes_mut(&mut self) -> &mut [Scope] {
&mut self.scope_stack[..self.scope_top]
&mut self.scope_stack
}
pub fn has_scope(&self) -> bool {
@ -61,30 +63,24 @@ impl<'a> Environment<'a> {
}
pub fn current_scope(&self) -> &Scope {
&self.scope_stack[self.scope_top - 1]
self.scope_stack.last().unwrap()
}
pub fn current_scope_mut(&mut self) -> &mut Scope {
&mut self.scope_stack[self.scope_top - 1]
self.scope_stack.last_mut().unwrap()
}
pub fn enter_scope(&mut self) {
// self.current_frame_mut().enter_scope();
// self.local_scopes.push(Scope::new());
if self.scope_top == self.scope_stack.len() {
self.scope_stack.push(Scope::default());
} else {
self.scope_stack[self.scope_top].clear();
}
self.scope_top += 1;
self.scope_stack.push(Scope::default());
}
pub fn exit_scope(&mut self) {
// self.current_frame_mut().exit_scope();
// self.local_scopes.pop().expect("Tried to pop global scope");
self.scope_top -= 1;
self.scope_stack.pop();
}
pub fn insert_closure(&mut self, closure: Scope) {
@ -108,14 +104,17 @@ impl<'a> Environment<'a> {
}
}
Err(RuntimeError::NameNotDefined { name: name.to_owned() })
Err(RuntimeError::NameNotDefined {
name: name.to_owned(),
})
// self.runtime.get_global(name)
}
pub fn define(&mut self, name: impl Into<String>, value: Value) {
pub fn define(&mut self, name: impl Into<Box<str>>, value: Value) {
if self.has_scope() {
let name = name.into();
self.current_scope_mut().insert(name, HeapedValue::new(value));
self.current_scope_mut()
.insert(name, HeapedValue::new(value));
} else {
self.runtime.define_global(name, value)
}
@ -133,7 +132,9 @@ impl<'a> Environment<'a> {
}
}
Err(RuntimeError::NameNotDefined { name: name.to_owned() })
Err(RuntimeError::NameNotDefined {
name: name.to_owned(),
})
// self.runtime.assign_global(name, value)
}
@ -145,12 +146,12 @@ impl<'a> Environment<'a> {
self.frames.pop().expect("Tried to pop global frame");
} */
pub fn collect_closure(&self, closure_vars: &[(String, usize)]) -> Scope {
pub fn collect_closure(&self, closure_vars: &[(Box<str>, usize)]) -> Scope {
let mut closure_scope = Scope::default();
for (name, level) in closure_vars {
// special injected variables
if name == "this" || name == "super" {
if &**name == "this" || &**name == "super" {
continue;
}
@ -181,7 +182,7 @@ impl Display for Environment<'_> {
write!(f, "\nScope {level}:")?;
for (name, value) in scope.iter() {
write!(f, "\n\t{name} = {value}")?;
write!(f, "\n\t{name} = {}", value.as_ref())?;
}
}

View file

@ -10,35 +10,43 @@ use crate::{LoxClass, ResolverError};
#[derive(Error, Debug)]
pub enum RuntimeError {
#[error("Unary operator {op} had invalid argument {arg}")]
#[error("RuntimeError: Unary operator {op} had invalid argument {arg}")]
UnaryOpInvalidArgument { op: UnaryOp, arg: Value },
#[error("Binary operator {op} had invalid arguments {left} and {right}")]
BinaryOpInvalidArguments { left: Value, op: BinaryOp, right: Value },
#[error("Division by zero")]
#[error("RuntimeError: Binary operator {op} had invalid arguments {left} and {right}")]
BinaryOpInvalidArguments {
left: Value,
op: BinaryOp,
right: Value,
},
#[error("RuntimeError: Division by zero")]
DivisionByZero,
#[error("Local {name} is not defined")]
#[error("RuntimeError: Local {name} is not defined")]
NameNotDefined { name: String },
#[error("Global {name} is not defined")]
#[error("RuntimeError: Global {name} is not defined")]
GlobalNotDefined { name: String },
#[error("{callee} is not callable")]
#[error("RuntimeError: {callee} is not callable")]
NotCallable { callee: Value },
#[error("{name}() takes {arity} args, but {given} were given.")]
WrongArity { name: String, arity: usize, given: usize },
#[error("Extern function call to {name} failed: {msg}")]
#[error("RuntimeError: {name}() takes {arity} args, but {given} were given.")]
WrongArity {
name: String,
arity: usize,
given: usize,
},
#[error("RuntimeError: Extern function call to {name} failed: {msg}")]
ExtFunCallFailed { name: String, msg: String },
#[error("Uncaught break statement")]
#[error("RuntimeError: Uncaught break statement")]
Break,
#[error("Uncaught return statement")]
#[error("RuntimeError: Uncaught return statement")]
Return { value: Value },
#[error("Exit with exit code {exit_code}")]
#[error("RuntimeError: Exit with exit code {exit_code}")]
Exit { exit_code: i32 },
#[error("Only objects have attributes")]
#[error("RuntimeError: Only objects have attributes")]
InvalidGetTarget,
#[error("Only objects have attributes")]
#[error("RuntimeError: Only objects have attributes")]
InvalidSetTarget,
#[error("Class {0} has no property {name}", class.name())]
UndefinedAttribute { class: Rc<LoxClass>, name: String },
#[error("{value} is not a valid superclass")]
#[error("RuntimeError: Class {0} has no property {name}", class.name())]
UndefinedAttribute { class: Rc<LoxClass>, name: Box<str> },
#[error("RuntimeError: {value} is not a valid superclass")]
InvalidSuperclass { value: Value },
}
@ -57,7 +65,7 @@ pub enum LoxError {
Exit { exit_code: i32 },
}
fn format_multiple_errors(errs: &Vec<impl std::error::Error>) -> String {
fn format_multiple_errors(errs: &[impl std::error::Error]) -> String {
let msg = if errs.len() == 1 {
errs[0].to_string()
} else {
@ -81,7 +89,9 @@ impl From<Vec<ParserError>> for LoxError {
impl From<ResolverError> for LoxError {
fn from(resolver_err: ResolverError) -> Self {
LoxError::ResolverError { inner: resolver_err }
LoxError::ResolverError {
inner: resolver_err,
}
}
}

View file

@ -11,14 +11,19 @@ use super::{Runtime, Value};
#[derive(Debug, Clone)]
pub struct LoxFunction {
name: String,
name: Box<str>,
closure: Scope,
param_names: Vec<String>,
param_names: Vec<Box<str>>,
body: Box<Stmt>,
}
impl LoxFunction {
pub fn new(name: impl Into<String>, closure: Scope, param_names: Vec<String>, body: Stmt) -> Rc<Self> {
pub fn new(
name: impl Into<Box<str>>,
closure: Scope,
param_names: Vec<Box<str>>,
body: Stmt,
) -> Rc<Self> {
let name = name.into();
let body = Box::new(body);
let fun = LoxFunction {
@ -38,7 +43,7 @@ impl LoxFunction {
&self.closure
}
pub fn param_names(&self) -> &[String] {
pub fn param_names(&self) -> &[Box<str>] {
&self.param_names
}
@ -50,7 +55,7 @@ impl LoxFunction {
self.param_names().len()
}
pub fn inject_closed_var(&mut self, name: impl Into<String>, value: Value) {
pub fn inject_closed_var(&mut self, name: impl Into<Box<str>>, value: Value) {
let name = name.into();
let heaped_value = HeapedValue::new(value);
self.closure.insert(name, heaped_value);
@ -88,7 +93,11 @@ impl LoxExternFunction {
pub fn new(name: impl Into<String>, arity: usize, closure: ExternFunClosure) -> Self {
let name = name.into();
LoxExternFunction { name, arity, closure }
LoxExternFunction {
name,
arity,
closure,
}
}
pub fn name(&self) -> &str {

View file

@ -31,7 +31,7 @@ trait Eval {
impl Eval for Literal {
fn eval(&self, _env: &mut Environment) -> EvalResult<Value> {
match self {
Literal::String(s) => Ok(Value::String(Rc::clone(s))),
Literal::String(s) => Ok(Value::String(s.clone())),
Literal::Number(num) => Ok(Value::Number(*num)),
Literal::Bool(b) => Ok(Value::Bool(*b)),
Literal::Nil => Ok(Value::Nil),
@ -83,10 +83,10 @@ impl Eval for Expr {
},
(String(left), String(right)) => match op {
BinaryOp::Add => {
let mut s = std::string::String::with_capacity(left.capacity() + right.capacity());
s += &left;
s += &right;
Ok(String(Rc::new(s)))
let s: Box<str> =
itertools::chain(left.as_ref().chars(), right.chars()).collect();
Ok(Value::string(s))
}
BinaryOp::Less => Ok(Bool(left < right)),
BinaryOp::LessEqual => Ok(Bool(left <= right)),
@ -99,14 +99,18 @@ impl Eval for Expr {
right: String(right),
}),
},
(left, right) => Err(RuntimeError::BinaryOpInvalidArguments { left, op, right }),
(left, right) => {
Err(RuntimeError::BinaryOpInvalidArguments { left, op, right })
}
}
}
Expr::Logical { left, op, right } => {
let left = left.eval(env)?;
// shortcircuit
if *op == LogicalOp::Or && left.is_truthy() || *op == LogicalOp::And && !left.is_truthy() {
if *op == LogicalOp::Or && left.is_truthy()
|| *op == LogicalOp::And && !left.is_truthy()
{
return Ok(left);
}
@ -121,7 +125,9 @@ impl Eval for Expr {
let value = value.eval(env)?;
match target.as_ref() {
Expr::LocalVariable { name, level } => env.assign(name, value.clone(), *level)?,
Expr::LocalVariable { name, level } => {
env.assign(name, value.clone(), *level)?
}
Expr::GlobalVariable { name } => env.assign_global(name, value.clone())?,
_ => panic!("Invalid assigment target {target}"),
}
@ -159,12 +165,16 @@ impl Eval for Expr {
Err(RuntimeError::InvalidGetTarget)
}
}
Expr::Set { target, name, value } => {
Expr::Set {
target,
name,
value,
} => {
let target = target.eval(env)?;
if let Value::Object(mut object) = target {
let value = value.eval(env)?;
object.set(name, value);
object.set(name.clone(), value);
Ok(Value::Nil)
} else {
Err(RuntimeError::InvalidSetTarget)
@ -176,7 +186,7 @@ impl Eval for Expr {
closure_vars,
body,
} => Ok(Value::function(LoxFunction::new(
name,
name.clone(),
env.collect_closure(closure_vars),
param_names.clone(),
body.as_ref().clone(),
@ -208,7 +218,11 @@ impl Eval for Expr {
env.exit_scope();
Ok(Value::class(LoxClass::new(name, methods, superclass)))
Ok(Value::class(LoxClass::new(
name.clone(),
methods,
superclass,
)))
}
Expr::This => panic!("Unresolved this"),
Expr::Super {
@ -223,7 +237,9 @@ impl Eval for Expr {
Err(RuntimeError::InvalidGetTarget)
}
}
(super_val, this_val) => panic!("super evaluated to {super_val} and this evaluated to {this_val}"),
(super_val, this_val) => {
panic!("super evaluated to {super_val} and this evaluated to {this_val}")
}
},
}
}
@ -233,11 +249,10 @@ impl Eval for Stmt {
fn eval(&self, env: &mut Environment) -> EvalResult<Value> {
match self {
Stmt::Print { expr } => {
match expr.eval(env)? {
// special case: when printing a string, drop the surrounding ""
Value::String(s) => println!("{s}"),
val => println!("{val}"),
}
use std::io::Write;
let val = expr.eval(env)?;
writeln!(env.runtime(), "{val}").unwrap();
}
Stmt::IfStmt {
condition,
@ -262,7 +277,7 @@ impl Eval for Stmt {
}
Stmt::VarDecl { name, initializer } => {
let initializer = initializer.eval(env)?;
env.define(name, initializer);
env.define(name.clone(), initializer);
}
Stmt::Block { statements } => {
env.enter_scope();
@ -310,7 +325,7 @@ pub fn call_fun(fun: Rc<LoxFunction>, env: &mut Environment) -> EvalResult<Value
env.insert_closure(fun.closure().clone());
for (name, value) in std::iter::zip(fun.param_names(), args) {
env.define(name, value);
env.define(name.clone(), value);
}
let ret_val = match fun.body().eval(env) {

View file

@ -47,7 +47,7 @@ fn clock() -> LoxExternFunction {
fn print_globals() -> LoxExternFunction {
let closure: ExternFunClosure = |args, env| {
assert_eq!(args.len(), 0);
let mut globals: Vec<(&String, &Value)> = env.globals().iter().collect();
let mut globals: Vec<(&Box<str>, &Value)> = env.globals().iter().collect();
globals.sort_by_key(|&(name, _value)| name);

View file

@ -12,7 +12,7 @@ use crate::{LoxClass, Value};
struct LoxObject {
class: Rc<LoxClass>,
attrs: FxHashMap<String, Value>,
attrs: FxHashMap<Box<str>, Value>,
}
impl LoxObject {
@ -35,7 +35,7 @@ impl LoxObject {
self.class.get_method(name, this)
}
fn set(&mut self, name: impl Into<String>, value: Value) {
fn set(&mut self, name: impl Into<Box<str>>, value: Value) {
let name = name.into();
self.attrs.insert(name, value);
}
@ -75,7 +75,7 @@ impl LoxReference {
}
}
pub fn set(&mut self, name: impl Into<String>, value: Value) {
pub fn set(&mut self, name: impl Into<Box<str>>, value: Value) {
unsafe {
let ptr = self.inner.get();
let object = &mut *ptr;
@ -99,7 +99,12 @@ impl Display for LoxReference {
unsafe {
let ptr = self.inner.get();
let object = &*ptr;
write!(f, "<{} object at {:#X}>", object.class().name(), ptr as usize)
write!(
f,
"<{} object at {:#X}>",
object.class().name(),
ptr as usize
)
}
}
}

View file

@ -6,7 +6,7 @@ use crate::{LoxError, ResolverError};
/*====================================================================================================================*/
type ResolverScope = FxHashMap<String, ResolveStatus>;
type ResolverScope = FxHashMap<Box<str>, ResolveStatus>;
type ResolverFrame = Vec<ResolverScope>;
/*====================================================================================================================*/
@ -35,11 +35,11 @@ struct Resolver {
// local_scopes: Vec<ResolverScope>,
frames: Vec<ResolverFrame>,
closure_vars: FxHashMap<String, usize>,
closure_vars: FxHashMap<Box<str>, usize>,
}
impl Resolver {
fn new(global_names: impl Iterator<Item = String>) -> Self {
fn new(global_names: impl Iterator<Item = Box<str>>) -> Self {
let mut global_scope = ResolverScope::default();
for name in global_names {
@ -76,11 +76,14 @@ impl Resolver {
}
fn pop_frame(&mut self) {
self.frames.pop().expect("Tried to pop non-existant ResolverFrame");
self.frames
.pop()
.expect("Tried to pop non-existant ResolverFrame");
}
fn declare(&mut self, name: &str) {
let name = name.to_owned();
fn declare(&mut self, name: impl Into<Box<str>>) {
let name = name.into();
if let Some(local_scope) = self.local_scopes_mut().last_mut() {
local_scope.insert(name, ResolveStatus::Declared);
} else {
@ -88,8 +91,9 @@ impl Resolver {
}
}
fn define(&mut self, name: &str) {
let name = name.to_owned();
fn define(&mut self, name: impl Into<Box<str>>) {
let name = name.into();
if let Some(local_scope) = self.local_scopes_mut().last_mut() {
local_scope.insert(name, ResolveStatus::Defined);
} else {
@ -106,38 +110,36 @@ impl Resolver {
}
fn resolve_var(&mut self, name: &str) -> Result<Expr, ResolverError> {
let name = name.to_owned();
let mut level = 0;
for scope in self.local_scopes().iter().rev() {
if scope.contains_key(&name) {
return Ok(Expr::LocalVariable { name, level });
if scope.contains_key(name) {
return Ok(Expr::local_variable(name, level));
}
level += 1;
}
for frame in self.frames.iter().rev().skip(1) {
for scope in frame.iter().rev() {
if scope.contains_key(&name) {
if !self.closure_vars.contains_key(&name) {
if scope.contains_key(name) {
if !self.closure_vars.contains_key(name) {
// the level at which the closed-over variable will be collected from
// from the perspective of the parameter/closure scope i.e. the outmost of the function
self.closure_vars
.insert(name.clone(), level - self.local_scopes().len());
.insert(name.into(), level - self.local_scopes().len());
}
return Ok(Expr::LocalVariable {
name,
// distance from actual variable refernce to parameter/closure scope
level: self.local_scopes().len() - 1,
});
// distance from actual variable refernce to parameter/closure scope
let level = self.local_scopes().len() - 1;
return Ok(Expr::local_variable(name, level));
}
level += 1;
}
}
if self.global_scope.contains_key(&name) {
return Ok(Expr::GlobalVariable { name });
if self.global_scope.contains_key(name) {
return Ok(Expr::global_variable(name));
}
if name == "this" {
@ -145,6 +147,7 @@ impl Resolver {
} else if name == "super" {
Err(ResolverError::SuperOutsideMethod)
} else {
let name = name.into();
Err(ResolverError::UnresolvableVariable { name })
}
}
@ -170,9 +173,9 @@ impl Resolver {
Ok(())
}
Stmt::VarDecl { name, initializer } => {
self.declare(name);
self.declare(name.clone());
self.resolve_expr(initializer)?;
self.define(name);
self.define(name.clone());
Ok(())
}
Stmt::Block { statements } => {
@ -244,7 +247,11 @@ impl Resolver {
self.resolve_expr(target)?;
Ok(())
}
Expr::Set { target, name: _, value } => {
Expr::Set {
target,
name: _,
value,
} => {
self.resolve_expr(target)?;
self.resolve_expr(value)?;
Ok(())
@ -259,12 +266,12 @@ impl Resolver {
self.push_frame();
self.declare(name);
self.define(name);
self.declare(name.clone());
self.define(name.clone());
for param_name in param_names.iter() {
self.declare(param_name);
self.define(param_name);
self.declare(param_name.clone());
self.define(param_name.clone());
}
self.resolve_stmt(body)?;
@ -284,13 +291,13 @@ impl Resolver {
name,
methods,
} => {
self.declare(name);
self.declare(name.clone());
if let Some(superclass) = superclass {
self.resolve_expr(superclass)?;
}
self.define(name);
self.define(name.clone());
// this is the scope "this" is defined in
self.enter_scope();

View file

@ -3,9 +3,9 @@ use thiserror::Error;
#[derive(Error, Debug)]
pub enum ResolverError {
#[error("Can't read variable {name} in its own initializer.")]
VarInOwnInitializer { name: String },
VarInOwnInitializer { name: Box<str> },
#[error("Variable {name} not defined")]
UnresolvableVariable { name: String },
UnresolvableVariable { name: Box<str> },
#[error("Return outside of function definition")]
ReturnOutsideFunction,
#[error("this outside of method")]

View file

@ -24,9 +24,12 @@ pub fn run_repl(runtime: &mut Runtime) {
std::process::exit(66);
});
let num_open_braces = (input_buf.matches('{').count() as i64) - (input_buf.matches('}').count() as i64);
let num_open_parens = (input_buf.matches('(').count() as i64) - (input_buf.matches(')').count() as i64);
let num_open_brackets = (input_buf.matches('[').count() as i64) - (input_buf.matches(']').count() as i64);
let num_open_braces =
(input_buf.matches('{').count() as i64) - (input_buf.matches('}').count() as i64);
let num_open_parens =
(input_buf.matches('(').count() as i64) - (input_buf.matches(')').count() as i64);
let num_open_brackets =
(input_buf.matches('[').count() as i64) - (input_buf.matches(']').count() as i64);
// all braces/parens/brackets closed => break
if num_open_braces == 0 && num_open_parens == 0 && num_open_brackets == 0 {
@ -47,12 +50,12 @@ pub fn run_repl(runtime: &mut Runtime) {
std::io::stdout().flush().unwrap();
}
let input_buf = input_buf.trim();
if input_buf.is_empty() || input_buf == "exit" || input_buf == "quit" {
if input_buf.is_empty() || input_buf == "exit\n" || input_buf == "quit\n" {
std::process::exit(0);
}
let input_buf = input_buf.trim();
match run(input_buf, runtime) {
Ok(()) => {}
Err(LoxError::Exit { exit_code }) => std::process::exit(exit_code),
@ -64,20 +67,25 @@ pub fn run_repl(runtime: &mut Runtime) {
pub fn run(source: &str, runtime: &mut Runtime) -> Result<(), LoxError> {
let tokens: Vec<Token> = scan_tokens(source)?;
let token_str = itertools::Itertools::join(&mut tokens.iter().map(|token| token.to_string()), " ");
if runtime.debug() {
let token_str =
itertools::Itertools::join(&mut tokens.iter().map(|token| token.to_string()), " ");
println!("{token_str}");
println!("{token_str}");
}
let statements = parse_tokens(tokens)?;
/* for statement in statements.iter() {
println!("{statement}");
} */
for mut statement in statements {
if runtime.debug() {
println!("{statement}");
}
resolve(&mut statement, runtime)?;
// println!("{statement}");
if runtime.debug() {
println!("{statement}");
}
execute(statement, runtime)?;
}

View file

@ -1,5 +1,7 @@
use std::cell::RefCell;
use std::fmt::Display;
use std::io::{stdin, stdout, Read, Write};
use std::rc::Rc;
use rustc_hash::FxHashMap;
@ -9,19 +11,24 @@ use super::lox_std::init_std;
use super::Value;
pub struct Runtime {
globals: FxHashMap<String, Value>,
globals: FxHashMap<Box<str>, Value>,
in_stream: Box<dyn std::io::BufRead>,
out_stream: Box<dyn std::io::Write>,
in_stream: Rc<RefCell<dyn std::io::Read>>,
out_stream: Rc<RefCell<dyn std::io::Write>>,
debug: bool,
}
impl Runtime {
pub fn new(in_stream: Box<dyn std::io::Read>, out_stream: Box<dyn std::io::Write>) -> Self {
let in_stream = Box::new(std::io::BufReader::new(in_stream));
pub fn new(
in_stream: Rc<RefCell<dyn std::io::Read>>,
out_stream: Rc<RefCell<dyn std::io::Write>>,
) -> Self {
let mut runtime = Runtime {
globals: FxHashMap::default(),
in_stream,
out_stream,
debug: false,
};
init_std(&mut runtime);
@ -29,7 +36,24 @@ impl Runtime {
runtime
}
pub fn globals(&self) -> &FxHashMap<String, Value> {
pub fn set_debug(&mut self, debug: bool) {
self.debug = debug;
}
pub fn debug(&self) -> bool {
self.debug
}
pub fn in_stream(&mut self) -> std::cell::RefMut<dyn std::io::Read> {
self.in_stream.as_ref().borrow_mut()
}
pub fn out_stream(&mut self) -> std::cell::RefMut<dyn std::io::Write> {
// &mut self.out_stream
self.out_stream.as_ref().borrow_mut()
}
pub fn globals(&self) -> &FxHashMap<Box<str>, Value> {
&self.globals
}
@ -37,10 +61,12 @@ impl Runtime {
self.globals
.get(name)
.cloned()
.ok_or_else(|| RuntimeError::GlobalNotDefined { name: name.to_owned() })
.ok_or_else(|| RuntimeError::GlobalNotDefined {
name: name.to_owned(),
})
}
pub fn define_global(&mut self, name: impl Into<String>, value: Value) {
pub fn define_global(&mut self, name: impl Into<Box<str>>, value: Value) {
let name = name.into();
self.globals.insert(name, value);
}
@ -50,20 +76,30 @@ impl Runtime {
*old_value = value;
Ok(())
} else {
Err(RuntimeError::GlobalNotDefined { name: name.to_owned() })
Err(RuntimeError::GlobalNotDefined {
name: name.to_owned(),
})
}
}
}
impl Default for Runtime {
fn default() -> Self {
Runtime::new(Box::new(std::io::BufReader::new(stdin())), Box::new(stdout()))
// let buf_reader = std::io::BufReader::new(stdin());
// let buf_reader_boxed = Box::new(&mut buf_reader);
let in_stream = Rc::new(RefCell::new(stdin()));
let out_stream = Rc::new(RefCell::new(stdout()));
Runtime::new(in_stream, out_stream)
}
}
impl std::fmt::Debug for Runtime {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Runtime").field("globals", &self.globals).finish()
f.debug_struct("Runtime")
.field("globals", &self.globals)
.finish()
}
}
@ -81,22 +117,22 @@ impl Display for Runtime {
impl Drop for Runtime {
fn drop(&mut self) {
self.out_stream.flush().unwrap();
self.out_stream().flush().unwrap();
}
}
impl Read for Runtime {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
self.in_stream.read(buf)
self.in_stream().read(buf)
}
}
impl Write for Runtime {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
self.out_stream.write(buf)
self.out_stream().write(buf)
}
fn flush(&mut self) -> std::io::Result<()> {
self.out_stream.flush()
self.out_stream().flush()
}
}

View file

@ -13,11 +13,12 @@ pub enum Value {
Class(Rc<LoxClass>),
Function(Rc<LoxFunction>),
ExternFunction(Rc<LoxExternFunction>),
String(Rc<String>),
String(Box<str>),
Number(f64),
Bool(bool),
Nil,
}
impl Value {
pub fn class(class: Rc<LoxClass>) -> Self {
Value::Class(class)
@ -33,8 +34,8 @@ impl Value {
Value::ExternFunction(fun)
}
pub fn string(s: impl Into<String>) -> Self {
let s = Rc::new(s.into());
pub fn string(s: impl Into<Box<str>>) -> Self {
let s = s.into();
Value::String(s)
}
@ -50,7 +51,7 @@ impl Display for Value {
Value::Class(class) => write!(f, "{class}"),
Value::Function(fun) => write!(f, "{fun}"),
Value::ExternFunction(ext_fun) => write!(f, "{ext_fun}"),
Value::String(s) => write!(f, "\"{s}\""),
Value::String(s) => write!(f, "{s}"),
Value::Number(num) => write!(f, "{num}"),
Value::Bool(b) => write!(f, "{b}"),
Value::Nil => write!(f, "nil"),
@ -60,7 +61,7 @@ impl Display for Value {
/*====================================================================================================================*/
#[derive(Clone)]
#[derive(Debug, Clone)]
pub struct HeapedValue {
inner: Rc<UnsafeCell<Value>>,
}
@ -88,14 +89,11 @@ impl HeapedValue {
}
}
impl Debug for HeapedValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("HeapValue").field("inner", &self.get_clone()).finish()
}
}
impl Display for HeapedValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.get_clone())
impl AsRef<Value> for HeapedValue {
fn as_ref(&self) -> &Value {
unsafe {
let ptr = self.inner.get();
&*ptr
}
}
}