mirror of
https://github.com/MorizzG/rlox.git
synced 2025-12-06 04:12:42 +00:00
Finished up to and including chapter 16
This commit is contained in:
parent
647a095a05
commit
b86985deaf
24 changed files with 1051 additions and 198 deletions
|
|
@ -1,8 +1,8 @@
|
|||
use std::collections::HashMap;
|
||||
use std::fmt::Display;
|
||||
use std::rc::Rc;
|
||||
|
||||
use rlox2_frontend::parser::{Expr, Stmt};
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use crate::{LoxFunction, LoxReference, Value};
|
||||
|
||||
|
|
@ -12,12 +12,16 @@ pub struct LoxClass {
|
|||
|
||||
name: String,
|
||||
|
||||
methods: HashMap<String, Value>,
|
||||
methods: FxHashMap<String, Value>,
|
||||
}
|
||||
|
||||
/// 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>, methods: HashMap<String, Value>, superclass: Option<Rc<LoxClass>>) -> Rc<Self> {
|
||||
pub fn new(
|
||||
name: impl Into<String>,
|
||||
methods: FxHashMap<String, Value>,
|
||||
superclass: Option<Rc<LoxClass>>,
|
||||
) -> Rc<Self> {
|
||||
let name = name.into();
|
||||
let mut methods = methods;
|
||||
|
||||
|
|
@ -42,7 +46,7 @@ impl LoxClass {
|
|||
}
|
||||
|
||||
if let Some(ref superclass) = superclass {
|
||||
let mut new_methods: HashMap<String, Value> = HashMap::new();
|
||||
let mut new_methods: FxHashMap<String, Value> = FxHashMap::default();
|
||||
|
||||
// Rc<LoxFunction> is immutable, so we need to drain, change, and replace
|
||||
for (name, value) in methods {
|
||||
|
|
|
|||
|
|
@ -1,48 +1,94 @@
|
|||
use std::collections::HashMap;
|
||||
use std::fmt::Display;
|
||||
use std::io::{Read, Write};
|
||||
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use crate::error::RuntimeError;
|
||||
|
||||
use super::value::HeapedValue;
|
||||
use super::{Runtime, Value};
|
||||
|
||||
pub type Scope = HashMap<String, HeapedValue>;
|
||||
pub type Scope = FxHashMap<String, HeapedValue>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Environment<'a> {
|
||||
local_scopes: Vec<Scope>,
|
||||
scope_stack: Vec<Scope>,
|
||||
scope_top: usize,
|
||||
|
||||
runtime: &'a mut Runtime,
|
||||
|
||||
arg_stack: Vec<Value>,
|
||||
}
|
||||
|
||||
impl<'a> Environment<'a> {
|
||||
pub fn new(runtime: &'a mut Runtime) -> Self {
|
||||
Environment {
|
||||
// globals: HashMap::new(),
|
||||
// frames: vec![Frame::new_global()],
|
||||
local_scopes: Vec::new(),
|
||||
scope_stack: Vec::new(),
|
||||
scope_top: 0,
|
||||
|
||||
runtime,
|
||||
|
||||
arg_stack: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn globals(&self) -> &HashMap<String, Value> {
|
||||
pub fn push_arg(&mut self, arg: Value) {
|
||||
self.arg_stack.push(arg);
|
||||
}
|
||||
|
||||
pub fn num_args(&self) -> usize {
|
||||
self.arg_stack.len()
|
||||
}
|
||||
|
||||
pub fn collect_args(&mut self) -> Vec<Value> {
|
||||
std::mem::take(&mut self.arg_stack)
|
||||
}
|
||||
|
||||
pub fn globals(&self) -> &FxHashMap<String, Value> {
|
||||
self.runtime.globals()
|
||||
}
|
||||
|
||||
pub fn scopes(&self) -> &[Scope] {
|
||||
&self.scope_stack[..self.scope_top]
|
||||
}
|
||||
|
||||
pub fn scopes_mut(&mut self) -> &mut [Scope] {
|
||||
&mut self.scope_stack[..self.scope_top]
|
||||
}
|
||||
|
||||
pub fn has_scope(&self) -> bool {
|
||||
!self.scope_stack.is_empty()
|
||||
}
|
||||
|
||||
pub fn current_scope(&self) -> &Scope {
|
||||
&self.scope_stack[self.scope_top - 1]
|
||||
}
|
||||
|
||||
pub fn current_scope_mut(&mut self) -> &mut Scope {
|
||||
&mut self.scope_stack[self.scope_top - 1]
|
||||
}
|
||||
|
||||
pub fn enter_scope(&mut self) {
|
||||
// self.current_frame_mut().enter_scope();
|
||||
self.local_scopes.push(Scope::new());
|
||||
// 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;
|
||||
}
|
||||
|
||||
pub fn exit_scope(&mut self) {
|
||||
// self.current_frame_mut().exit_scope();
|
||||
self.local_scopes.pop().expect("Tried to pop global scope");
|
||||
// self.local_scopes.pop().expect("Tried to pop global scope");
|
||||
self.scope_top -= 1;
|
||||
}
|
||||
|
||||
pub fn insert_closure(&mut self, closure: Scope) {
|
||||
let scope = self.local_scopes.last_mut().unwrap();
|
||||
let scope = self.current_scope_mut();
|
||||
|
||||
for (name, value) in closure {
|
||||
scope.insert(name, value);
|
||||
|
|
@ -54,9 +100,10 @@ impl<'a> Environment<'a> {
|
|||
}
|
||||
|
||||
pub fn get_local(&self, name: &str, level: usize) -> Result<Value, RuntimeError> {
|
||||
let len = self.local_scopes.len();
|
||||
let len = self.scopes().len();
|
||||
|
||||
if level < len {
|
||||
if let Some(heap_value) = self.local_scopes[len - level - 1].get(name) {
|
||||
if let Some(heap_value) = self.scopes()[len - level - 1].get(name) {
|
||||
return Ok(heap_value.get_clone());
|
||||
}
|
||||
}
|
||||
|
|
@ -66,9 +113,9 @@ impl<'a> Environment<'a> {
|
|||
}
|
||||
|
||||
pub fn define(&mut self, name: impl Into<String>, value: Value) {
|
||||
if let Some(scope) = self.local_scopes.last_mut() {
|
||||
if self.has_scope() {
|
||||
let name = name.into();
|
||||
scope.insert(name, HeapedValue::new(value));
|
||||
self.current_scope_mut().insert(name, HeapedValue::new(value));
|
||||
} else {
|
||||
self.runtime.define_global(name, value)
|
||||
}
|
||||
|
|
@ -79,7 +126,7 @@ impl<'a> Environment<'a> {
|
|||
}
|
||||
|
||||
pub fn assign(&mut self, name: &str, value: Value, level: usize) -> Result<(), RuntimeError> {
|
||||
if let Some(scope) = self.local_scopes.iter_mut().rev().nth(level) {
|
||||
if let Some(scope) = self.scopes_mut().iter_mut().rev().nth(level) {
|
||||
if let Some(heap_value) = scope.get_mut(name) {
|
||||
heap_value.replace(value);
|
||||
return Ok(());
|
||||
|
|
@ -99,7 +146,7 @@ impl<'a> Environment<'a> {
|
|||
} */
|
||||
|
||||
pub fn collect_closure(&self, closure_vars: &[(String, usize)]) -> Scope {
|
||||
let mut closure_scope = Scope::new();
|
||||
let mut closure_scope = Scope::default();
|
||||
|
||||
for (name, level) in closure_vars {
|
||||
// special injected variables
|
||||
|
|
@ -108,7 +155,7 @@ impl<'a> Environment<'a> {
|
|||
}
|
||||
|
||||
let heap_value = self
|
||||
.local_scopes
|
||||
.scopes()
|
||||
.iter()
|
||||
.rev()
|
||||
.nth(*level)
|
||||
|
|
@ -130,7 +177,7 @@ impl Display for Environment<'_> {
|
|||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.runtime)?;
|
||||
|
||||
for (level, scope) in self.local_scopes.iter().enumerate() {
|
||||
for (level, scope) in self.scopes().iter().enumerate() {
|
||||
write!(f, "\nScope {level}:")?;
|
||||
|
||||
for (name, value) in scope.iter() {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
|
||||
use rlox2_frontend::parser::{BinaryOp, Expr, Literal, LogicalOp, Stmt, UnaryOp};
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use crate::error::RuntimeError;
|
||||
use crate::function::LoxExternFunction;
|
||||
|
|
@ -29,8 +29,7 @@ trait Eval {
|
|||
}
|
||||
|
||||
impl Eval for Literal {
|
||||
fn eval(&self, env: &mut Environment) -> EvalResult<Value> {
|
||||
let _ = env;
|
||||
fn eval(&self, _env: &mut Environment) -> EvalResult<Value> {
|
||||
match self {
|
||||
Literal::String(s) => Ok(Value::String(Rc::clone(s))),
|
||||
Literal::Number(num) => Ok(Value::Number(*num)),
|
||||
|
|
@ -57,57 +56,60 @@ impl Eval for Expr {
|
|||
Expr::Binary { left, op, right } => {
|
||||
use Value::{Bool, Number, String};
|
||||
|
||||
let op = *op;
|
||||
|
||||
let left = left.eval(env)?;
|
||||
let right = right.eval(env)?;
|
||||
|
||||
match (left, *op, right) {
|
||||
(Number(left), BinaryOp::Add, Number(right)) => Ok(Number(left + right)),
|
||||
(Number(left), BinaryOp::Subtract, Number(right)) => Ok(Number(left - right)),
|
||||
(Number(left), BinaryOp::Multiply, Number(right)) => Ok(Number(left * right)),
|
||||
(Number(left), BinaryOp::Divide, Number(right)) => {
|
||||
if right == 0.0 {
|
||||
return Err(RuntimeError::DivisionByZero);
|
||||
if op == BinaryOp::Equal {
|
||||
return Ok(Bool(left == right));
|
||||
}
|
||||
|
||||
if op == BinaryOp::NotEqual {
|
||||
return Ok(Bool(left != right));
|
||||
}
|
||||
|
||||
match (left, right) {
|
||||
(Number(left), Number(right)) => match op {
|
||||
BinaryOp::Add => Ok(Number(left + right)),
|
||||
BinaryOp::Subtract => Ok(Number(left - right)),
|
||||
BinaryOp::Multiply => Ok(Number(left * right)),
|
||||
BinaryOp::Divide => Ok(Number(left / right)),
|
||||
BinaryOp::Less => Ok(Bool(left < right)),
|
||||
BinaryOp::LessEqual => Ok(Bool(left <= right)),
|
||||
BinaryOp::Greater => Ok(Bool(left > right)),
|
||||
BinaryOp::GreaterEqual => Ok(Bool(left >= right)),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
(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)))
|
||||
}
|
||||
Ok(Number(left / right))
|
||||
}
|
||||
|
||||
(String(left), BinaryOp::Add, String(right)) => {
|
||||
let mut s = std::string::String::with_capacity(left.capacity() + right.capacity());
|
||||
s += &left;
|
||||
s += &right;
|
||||
Ok(String(Rc::new(s)))
|
||||
}
|
||||
|
||||
(left, BinaryOp::Equal, right) => Ok(Bool(left == right)),
|
||||
(left, BinaryOp::NotEqual, right) => Ok(Bool(left != right)),
|
||||
|
||||
(Number(left), BinaryOp::Less, Number(right)) => Ok(Bool(left < right)),
|
||||
(Number(left), BinaryOp::LessEqual, Number(right)) => Ok(Bool(left <= right)),
|
||||
(Number(left), BinaryOp::Greater, Number(right)) => Ok(Bool(left > right)),
|
||||
(Number(left), BinaryOp::GreaterEqual, Number(right)) => Ok(Bool(left >= right)),
|
||||
|
||||
(String(left), BinaryOp::Less, String(right)) => Ok(Bool(left < right)),
|
||||
(String(left), BinaryOp::LessEqual, String(right)) => Ok(Bool(left <= right)),
|
||||
(String(left), BinaryOp::Greater, String(right)) => Ok(Bool(left > right)),
|
||||
(String(left), BinaryOp::GreaterEqual, String(right)) => Ok(Bool(left >= right)),
|
||||
|
||||
(left, op, right) => Err(RuntimeError::BinaryOpInvalidArguments { left, op, right }),
|
||||
BinaryOp::Less => Ok(Bool(left < right)),
|
||||
BinaryOp::LessEqual => Ok(Bool(left <= right)),
|
||||
BinaryOp::Greater => Ok(Bool(left > right)),
|
||||
BinaryOp::GreaterEqual => Ok(Bool(left >= right)),
|
||||
BinaryOp::Equal | BinaryOp::NotEqual => unreachable!(),
|
||||
_ => Err(RuntimeError::BinaryOpInvalidArguments {
|
||||
left: String(left),
|
||||
op,
|
||||
right: String(right),
|
||||
}),
|
||||
},
|
||||
(left, right) => Err(RuntimeError::BinaryOpInvalidArguments { left, op, right }),
|
||||
}
|
||||
}
|
||||
Expr::Logical { left, op, right } => {
|
||||
let left = left.eval(env)?;
|
||||
match op {
|
||||
LogicalOp::Or => {
|
||||
if left.is_truthy() {
|
||||
return Ok(left);
|
||||
}
|
||||
}
|
||||
LogicalOp::And => {
|
||||
if !left.is_truthy() {
|
||||
return Ok(left);
|
||||
}
|
||||
}
|
||||
|
||||
// shortcircuit
|
||||
if *op == LogicalOp::Or && left.is_truthy() || *op == LogicalOp::And && !left.is_truthy() {
|
||||
return Ok(left);
|
||||
}
|
||||
|
||||
let right = right.eval(env)?;
|
||||
Ok(right)
|
||||
}
|
||||
|
|
@ -127,15 +129,20 @@ impl Eval for Expr {
|
|||
}
|
||||
Expr::Call { callee, args } => {
|
||||
let callee = callee.eval(env)?;
|
||||
let args = args
|
||||
.iter()
|
||||
.map(|arg| arg.eval(env))
|
||||
.collect::<EvalResult<Vec<Value>>>()?;
|
||||
/* let args = args
|
||||
.iter()
|
||||
.map(|arg| arg.eval(env))
|
||||
.collect::<EvalResult<Vec<Value>>>()?; */
|
||||
|
||||
for arg in args {
|
||||
let arg = arg.eval(env)?;
|
||||
env.push_arg(arg);
|
||||
}
|
||||
|
||||
match callee {
|
||||
Value::Function(fun) => LoxFunction::call(fun, args, env),
|
||||
Value::ExternFunction(ext_fun) => ext_fun.call(args, env),
|
||||
Value::Class(class) => LoxClass::call(class, args, env),
|
||||
Value::Function(fun) => call_fun(fun, env),
|
||||
Value::ExternFunction(ext_fun) => call_extfun(ext_fun, env),
|
||||
Value::Class(class) => call_class(class, env),
|
||||
_ => Err(RuntimeError::NotCallable { callee }),
|
||||
}
|
||||
}
|
||||
|
|
@ -169,9 +176,9 @@ impl Eval for Expr {
|
|||
closure_vars,
|
||||
body,
|
||||
} => Ok(Value::function(LoxFunction::new(
|
||||
name.as_ref(),
|
||||
name,
|
||||
env.collect_closure(closure_vars),
|
||||
param_names.as_ref().clone(),
|
||||
param_names.clone(),
|
||||
body.as_ref().clone(),
|
||||
))),
|
||||
Expr::Class {
|
||||
|
|
@ -186,7 +193,7 @@ impl Eval for Expr {
|
|||
None => None,
|
||||
};
|
||||
|
||||
let mut methods: HashMap<String, Value> = HashMap::new();
|
||||
let mut methods: FxHashMap<String, Value> = FxHashMap::default();
|
||||
|
||||
// this is the scope "this" will get injected in
|
||||
env.enter_scope();
|
||||
|
|
@ -285,71 +292,71 @@ impl Eval for Stmt {
|
|||
|
||||
/*====================================================================================================================*/
|
||||
|
||||
impl LoxFunction {
|
||||
pub fn call(fun: Rc<LoxFunction>, args: Vec<Value>, env: &mut Environment) -> EvalResult<Value> {
|
||||
if args.len() != fun.arity() {
|
||||
return Err(RuntimeError::WrongArity {
|
||||
name: fun.name().to_owned(),
|
||||
arity: fun.arity(),
|
||||
given: args.len(),
|
||||
});
|
||||
}
|
||||
pub fn call_fun(fun: Rc<LoxFunction>, env: &mut Environment) -> EvalResult<Value> {
|
||||
let args = env.collect_args();
|
||||
|
||||
env.enter_scope();
|
||||
|
||||
env.define(fun.name(), Value::Function(fun.clone()));
|
||||
|
||||
env.insert_closure(fun.closure().clone());
|
||||
|
||||
for (name, value) in std::iter::zip(fun.param_names(), args) {
|
||||
env.define(name, value);
|
||||
}
|
||||
|
||||
let ret_val = match fun.body().eval(env) {
|
||||
Ok(_) => Ok(Value::Nil),
|
||||
Err(RuntimeError::Return { value }) => Ok(value),
|
||||
Err(err) => Err(err),
|
||||
};
|
||||
|
||||
env.exit_scope();
|
||||
|
||||
ret_val
|
||||
if args.len() != fun.arity() {
|
||||
return Err(RuntimeError::WrongArity {
|
||||
name: fun.name().to_owned(),
|
||||
arity: fun.arity(),
|
||||
given: args.len(),
|
||||
});
|
||||
}
|
||||
|
||||
env.enter_scope();
|
||||
|
||||
env.define(fun.name(), Value::Function(fun.clone()));
|
||||
|
||||
env.insert_closure(fun.closure().clone());
|
||||
|
||||
for (name, value) in std::iter::zip(fun.param_names(), args) {
|
||||
env.define(name, value);
|
||||
}
|
||||
|
||||
let ret_val = match fun.body().eval(env) {
|
||||
Ok(_) => Ok(Value::Nil),
|
||||
Err(RuntimeError::Return { value }) => Ok(value),
|
||||
Err(err) => Err(err),
|
||||
};
|
||||
|
||||
env.exit_scope();
|
||||
|
||||
ret_val
|
||||
}
|
||||
|
||||
impl LoxExternFunction {
|
||||
pub fn call(&self, args: Vec<Value>, env: &mut Environment) -> EvalResult<Value> {
|
||||
if args.len() != self.arity() {
|
||||
return Err(RuntimeError::WrongArity {
|
||||
name: self.name().to_owned(),
|
||||
arity: self.arity(),
|
||||
given: args.len(),
|
||||
});
|
||||
}
|
||||
pub fn call_extfun(ext_fun: Rc<LoxExternFunction>, env: &mut Environment) -> EvalResult<Value> {
|
||||
let args = env.collect_args();
|
||||
|
||||
(self.closure())(args, env)
|
||||
if args.len() != ext_fun.arity() {
|
||||
return Err(RuntimeError::WrongArity {
|
||||
name: ext_fun.name().to_owned(),
|
||||
arity: ext_fun.arity(),
|
||||
given: args.len(),
|
||||
});
|
||||
}
|
||||
|
||||
(ext_fun.closure())(args, env)
|
||||
}
|
||||
|
||||
impl LoxClass {
|
||||
// has to take class as an argument instead of as self to leave it behind its Rc
|
||||
pub fn call(class: Rc<LoxClass>, args: Vec<Value>, env: &mut Environment) -> EvalResult<Value> {
|
||||
if args.len() != class.arity() {
|
||||
return Err(RuntimeError::WrongArity {
|
||||
name: class.name().to_owned(),
|
||||
arity: class.arity(),
|
||||
given: args.len(),
|
||||
});
|
||||
}
|
||||
// has to take class as an argument instead of as self to leave it behind its Rc
|
||||
pub fn call_class(class: Rc<LoxClass>, env: &mut Environment) -> EvalResult<Value> {
|
||||
// let args = env.collect_args();
|
||||
|
||||
let object = LoxReference::new(class);
|
||||
|
||||
// object.init(args, env)?;
|
||||
|
||||
if let Some(Value::Function(method)) = object.get("init") {
|
||||
LoxFunction::call(method, args, env)?;
|
||||
}
|
||||
|
||||
Ok(Value::Object(object))
|
||||
if env.num_args() != class.arity() {
|
||||
return Err(RuntimeError::WrongArity {
|
||||
name: class.name().to_owned(),
|
||||
arity: class.arity(),
|
||||
given: env.num_args(),
|
||||
});
|
||||
}
|
||||
|
||||
let object = LoxReference::new(class);
|
||||
|
||||
// object.init(args, env)?;
|
||||
|
||||
if let Some(Value::Function(method)) = object.get("init") {
|
||||
call_fun(method, env)?;
|
||||
}
|
||||
|
||||
Ok(Value::Object(object))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,6 @@ pub use error::{LoxError, RuntimeError};
|
|||
pub use function::LoxFunction;
|
||||
pub use object::LoxReference;
|
||||
pub use resolver::{resolve, ResolverError};
|
||||
pub use run::{run_file, run_repl};
|
||||
pub use run::{run, run_repl};
|
||||
pub use runtime::Runtime;
|
||||
pub use value::Value;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
use std::cell::UnsafeCell;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Display;
|
||||
use std::rc::Rc;
|
||||
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use crate::{LoxClass, Value};
|
||||
|
||||
/// This struct is private, since *nothing* is supposed to be handling an object directly,
|
||||
|
|
@ -11,14 +12,14 @@ use crate::{LoxClass, Value};
|
|||
struct LoxObject {
|
||||
class: Rc<LoxClass>,
|
||||
|
||||
attrs: HashMap<String, Value>,
|
||||
attrs: FxHashMap<String, Value>,
|
||||
}
|
||||
|
||||
impl LoxObject {
|
||||
fn new(class: Rc<LoxClass>) -> Self {
|
||||
LoxObject {
|
||||
class,
|
||||
attrs: HashMap::new(),
|
||||
attrs: FxHashMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +1,12 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use rlox2_frontend::parser::{Expr, Stmt};
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use crate::Runtime;
|
||||
use crate::{LoxError, ResolverError};
|
||||
|
||||
/*====================================================================================================================*/
|
||||
|
||||
type ResolverScope = HashMap<String, ResolveStatus>;
|
||||
type ResolverScope = FxHashMap<String, ResolveStatus>;
|
||||
type ResolverFrame = Vec<ResolverScope>;
|
||||
|
||||
/*====================================================================================================================*/
|
||||
|
|
@ -36,12 +35,12 @@ struct Resolver {
|
|||
// local_scopes: Vec<ResolverScope>,
|
||||
frames: Vec<ResolverFrame>,
|
||||
|
||||
closure_vars: HashMap<String, usize>,
|
||||
closure_vars: FxHashMap<String, usize>,
|
||||
}
|
||||
|
||||
impl Resolver {
|
||||
fn new(global_names: impl Iterator<Item = String>) -> Self {
|
||||
let mut global_scope = ResolverScope::new();
|
||||
let mut global_scope = ResolverScope::default();
|
||||
|
||||
for name in global_names {
|
||||
global_scope.insert(name, ResolveStatus::Defined);
|
||||
|
|
@ -50,7 +49,7 @@ impl Resolver {
|
|||
Resolver {
|
||||
global_scope,
|
||||
frames: vec![ResolverFrame::new()],
|
||||
closure_vars: HashMap::new(),
|
||||
closure_vars: FxHashMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -63,7 +62,7 @@ impl Resolver {
|
|||
}
|
||||
|
||||
fn enter_scope(&mut self) {
|
||||
self.local_scopes_mut().push(ResolverScope::new());
|
||||
self.local_scopes_mut().push(ResolverScope::default());
|
||||
}
|
||||
|
||||
fn exit_scope(&mut self) {
|
||||
|
|
@ -73,7 +72,7 @@ impl Resolver {
|
|||
}
|
||||
|
||||
fn push_frame(&mut self) {
|
||||
self.frames.push(vec![ResolverScope::new()]);
|
||||
self.frames.push(vec![ResolverScope::default()]);
|
||||
}
|
||||
|
||||
fn pop_frame(&mut self) {
|
||||
|
|
|
|||
|
|
@ -9,32 +9,6 @@ use crate::resolver::resolve;
|
|||
|
||||
use super::Runtime;
|
||||
|
||||
pub fn run_file(runtime: &mut Runtime, script_path: &str) {
|
||||
let source_code = std::fs::read_to_string(script_path).unwrap_or_else(|err| {
|
||||
eprintln!("Reading script file {script_path} failed: {err}");
|
||||
std::process::exit(66);
|
||||
});
|
||||
|
||||
/* if let Err(err) = run(&source_code) {
|
||||
eprintln!("{}", err);
|
||||
std::process::exit(65);
|
||||
} */
|
||||
|
||||
match run(&source_code, runtime) {
|
||||
Ok(()) => {}
|
||||
Err(err) => {
|
||||
eprintln!("{err}");
|
||||
match err {
|
||||
LoxError::LexerError { .. } | LoxError::ParserError { .. } | LoxError::ResolverError { .. } => {
|
||||
std::process::exit(65)
|
||||
}
|
||||
LoxError::RuntimeError { .. } => std::process::exit(70),
|
||||
LoxError::Exit { exit_code } => std::process::exit(exit_code),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_repl(runtime: &mut Runtime) {
|
||||
let stdin = std::io::stdin();
|
||||
|
||||
|
|
@ -87,8 +61,8 @@ pub fn run_repl(runtime: &mut Runtime) {
|
|||
}
|
||||
}
|
||||
|
||||
fn run(code_string: &str, runtime: &mut Runtime) -> Result<(), LoxError> {
|
||||
let tokens: Vec<Token> = scan_tokens(code_string)?;
|
||||
pub fn run(source: &str, runtime: &mut Runtime) -> Result<(), LoxError> {
|
||||
let tokens: Vec<Token> = scan_tokens(source)?;
|
||||
|
||||
/* let token_str = tokens
|
||||
.iter()
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
use std::collections::HashMap;
|
||||
use std::fmt::Display;
|
||||
use std::io::{stdin, stdout, Read, Write};
|
||||
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use crate::error::RuntimeError;
|
||||
|
||||
use super::lox_std::init_std;
|
||||
use super::Value;
|
||||
|
||||
pub struct Runtime {
|
||||
globals: HashMap<String, Value>,
|
||||
globals: FxHashMap<String, Value>,
|
||||
|
||||
in_stream: Box<dyn std::io::BufRead>,
|
||||
out_stream: Box<dyn std::io::Write>,
|
||||
|
|
@ -18,7 +19,7 @@ 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));
|
||||
let mut runtime = Runtime {
|
||||
globals: HashMap::new(),
|
||||
globals: FxHashMap::default(),
|
||||
in_stream,
|
||||
out_stream,
|
||||
};
|
||||
|
|
@ -28,7 +29,7 @@ impl Runtime {
|
|||
runtime
|
||||
}
|
||||
|
||||
pub fn globals(&self) -> &HashMap<String, Value> {
|
||||
pub fn globals(&self) -> &FxHashMap<String, Value> {
|
||||
&self.globals
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue