Interpreter - WIP refactor to prepare for using resolved variables
This commit is contained in:
parent
d528ce8dc3
commit
10223cbb4e
6 changed files with 104 additions and 79 deletions
|
@ -2,17 +2,17 @@ use std::{cell::RefCell, fmt::Debug, rc::Rc};
|
||||||
|
|
||||||
use crate::errors::SloxResult;
|
use crate::errors::SloxResult;
|
||||||
|
|
||||||
use super::{EnvironmentRef, Value};
|
use super::{InterpreterState, Value};
|
||||||
|
|
||||||
/// A callable is some object that supports being called.
|
/// A callable is some object that supports being called.
|
||||||
pub trait Callable: Debug + ToString {
|
pub(super) trait Callable: Debug + ToString {
|
||||||
/// Return the amount of arguments supported by the callable.
|
/// Return the amount of arguments supported by the callable.
|
||||||
fn arity(&self) -> usize;
|
fn arity(&self) -> usize;
|
||||||
|
|
||||||
/// Run the callable in the execution environment with the specified
|
/// Run the callable in the execution environment with the specified
|
||||||
/// arguments.
|
/// arguments.
|
||||||
fn call(&self, environment: &EnvironmentRef, arguments: Vec<Value>) -> SloxResult<Value>;
|
fn call(&self, environment: &mut InterpreterState, arguments: Vec<Value>) -> SloxResult<Value>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A reference to a callable.
|
/// A reference to a callable.
|
||||||
pub type CallableRef = Rc<RefCell<dyn Callable>>;
|
pub(super) type CallableRef = Rc<RefCell<dyn Callable>>;
|
||||||
|
|
|
@ -8,15 +8,15 @@ use crate::{
|
||||||
use super::{native_fn, CallableRef, Value};
|
use super::{native_fn, CallableRef, Value};
|
||||||
|
|
||||||
/// A mutable reference to an environment.
|
/// A mutable reference to an environment.
|
||||||
pub type EnvironmentRef = Rc<RefCell<Environment>>;
|
pub(super) type EnvironmentRef = Rc<RefCell<Environment>>;
|
||||||
|
|
||||||
/// A variable.
|
/// A variable.
|
||||||
pub type Variable = Option<Value>;
|
pub(super) type Variable = Option<Value>;
|
||||||
|
|
||||||
/// The execution environment.
|
/// The execution environment.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Environment {
|
pub(super) struct Environment {
|
||||||
enclosing: Option<EnvironmentRef>,
|
pub(super) enclosing: Option<EnvironmentRef>,
|
||||||
values: HashMap<String, Variable>,
|
values: HashMap<String, Variable>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,14 +2,10 @@ use std::{cell::RefCell, rc::Rc};
|
||||||
|
|
||||||
use itertools::izip;
|
use itertools::izip;
|
||||||
|
|
||||||
use crate::{
|
use super::{
|
||||||
ast,
|
Callable, Environment, Interpretable, InterpreterFlowControl, InterpreterState, Value,
|
||||||
errors::SloxResult,
|
|
||||||
interpreter::{Environment, Interpretable, InterpreterFlowControl},
|
|
||||||
tokens::Token,
|
|
||||||
};
|
};
|
||||||
|
use crate::{ast, errors::SloxResult, tokens::Token};
|
||||||
use super::{Callable, EnvironmentRef, Value};
|
|
||||||
|
|
||||||
/// A function implemented in the Lox-ish language.
|
/// A function implemented in the Lox-ish language.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -39,16 +35,28 @@ impl Callable for Function {
|
||||||
self.params.len()
|
self.params.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(&self, environment: &EnvironmentRef, arguments: Vec<Value>) -> SloxResult<Value> {
|
fn call(&self, es: &mut InterpreterState, arguments: Vec<Value>) -> SloxResult<Value> {
|
||||||
assert_eq!(arguments.len(), self.arity());
|
assert_eq!(arguments.len(), self.arity());
|
||||||
let param_env = Environment::create_child(environment);
|
let param_env = InterpreterState {
|
||||||
|
environment: Environment::create_child(&es.environment),
|
||||||
|
globals: es.globals.clone(),
|
||||||
|
variables: es.variables,
|
||||||
|
};
|
||||||
for (arg, value) in izip!(self.params.iter(), arguments.into_iter()) {
|
for (arg, value) in izip!(self.params.iter(), arguments.into_iter()) {
|
||||||
param_env.borrow_mut().define(arg, Some(value)).unwrap();
|
param_env
|
||||||
|
.environment
|
||||||
|
.borrow_mut()
|
||||||
|
.define(arg, Some(value))
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
let child = Environment::create_child(¶m_env);
|
let mut child = InterpreterState {
|
||||||
|
environment: Environment::create_child(¶m_env.environment),
|
||||||
|
globals: es.globals.clone(),
|
||||||
|
variables: es.variables,
|
||||||
|
};
|
||||||
for stmt in self.body.iter() {
|
for stmt in self.body.iter() {
|
||||||
let result = stmt.interpret(&child)?;
|
let result = stmt.interpret(&mut child)?;
|
||||||
match result {
|
match result {
|
||||||
InterpreterFlowControl::Result(_) => (),
|
InterpreterFlowControl::Result(_) => (),
|
||||||
InterpreterFlowControl::Return(v) => return Ok(v),
|
InterpreterFlowControl::Return(v) => return Ok(v),
|
||||||
|
|
|
@ -11,13 +11,26 @@ use crate::{
|
||||||
/// Evaluate an interpretable, returning its value.
|
/// Evaluate an interpretable, returning its value.
|
||||||
pub fn evaluate(ast: &ast::ProgramNode, vars: ResolvedVariables) -> SloxResult<Value> {
|
pub fn evaluate(ast: &ast::ProgramNode, vars: ResolvedVariables) -> SloxResult<Value> {
|
||||||
let env = Rc::new(RefCell::new(Environment::default()));
|
let env = Rc::new(RefCell::new(Environment::default()));
|
||||||
ast.interpret(&env).map(|v| v.result())
|
let mut state = InterpreterState{
|
||||||
|
environment: env.clone(),
|
||||||
|
globals: env,
|
||||||
|
variables: &vars,
|
||||||
|
};
|
||||||
|
ast.interpret(&mut state).map(|v| v.result())
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------- *
|
/* ------- *
|
||||||
* HELPERS *
|
* HELPERS *
|
||||||
* ------- */
|
* ------- */
|
||||||
|
|
||||||
|
/// The state of the interpreter.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(super) struct InterpreterState<'a> {
|
||||||
|
pub(super) globals: EnvironmentRef,
|
||||||
|
pub(super) environment: EnvironmentRef,
|
||||||
|
pub(super) variables: &'a ResolvedVariables,
|
||||||
|
}
|
||||||
|
|
||||||
/// Interpreter flow control, which may be either a value, a loop break or a
|
/// Interpreter flow control, which may be either a value, a loop break or a
|
||||||
/// loop continuation.
|
/// loop continuation.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -62,7 +75,7 @@ pub(super) type InterpreterResult = SloxResult<InterpreterFlowControl>;
|
||||||
|
|
||||||
/// An Interpretable can be evaluated and will return a value.
|
/// An Interpretable can be evaluated and will return a value.
|
||||||
pub(super) trait Interpretable {
|
pub(super) trait Interpretable {
|
||||||
fn interpret(&self, environment: &EnvironmentRef) -> InterpreterResult;
|
fn interpret(&self, es: &mut InterpreterState) -> InterpreterResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate an error with a static message.
|
/// Generate an error with a static message.
|
||||||
|
@ -79,9 +92,9 @@ fn error<T>(token: &Token, message: &str) -> SloxResult<T> {
|
||||||
* ----------------------------- */
|
* ----------------------------- */
|
||||||
|
|
||||||
impl Interpretable for ast::ProgramNode {
|
impl Interpretable for ast::ProgramNode {
|
||||||
fn interpret(&self, environment: &EnvironmentRef) -> InterpreterResult {
|
fn interpret(&self, es: &mut InterpreterState) -> InterpreterResult {
|
||||||
for stmt in self.0.iter() {
|
for stmt in self.0.iter() {
|
||||||
stmt.interpret(environment)?;
|
stmt.interpret(es)?;
|
||||||
}
|
}
|
||||||
Ok(InterpreterFlowControl::default())
|
Ok(InterpreterFlowControl::default())
|
||||||
}
|
}
|
||||||
|
@ -92,32 +105,32 @@ impl Interpretable for ast::ProgramNode {
|
||||||
* ------------------------------- */
|
* ------------------------------- */
|
||||||
|
|
||||||
impl Interpretable for ast::StmtNode {
|
impl Interpretable for ast::StmtNode {
|
||||||
fn interpret(&self, environment: &EnvironmentRef) -> InterpreterResult {
|
fn interpret(&self, es: &mut InterpreterState) -> InterpreterResult {
|
||||||
match self {
|
match self {
|
||||||
ast::StmtNode::VarDecl(name, expr) => self.on_var_decl(environment, name, expr),
|
ast::StmtNode::VarDecl(name, expr) => self.on_var_decl(es, name, expr),
|
||||||
ast::StmtNode::FunDecl { name, params, body } => {
|
ast::StmtNode::FunDecl { name, params, body } => {
|
||||||
self.on_fun_decl(environment, name, params, body)
|
self.on_fun_decl(es, name, params, body)
|
||||||
}
|
}
|
||||||
ast::StmtNode::Expression(expr) => expr.interpret(environment),
|
ast::StmtNode::Expression(expr) => expr.interpret(es),
|
||||||
ast::StmtNode::Print(expr) => self.on_print(environment, expr),
|
ast::StmtNode::Print(expr) => self.on_print(es, expr),
|
||||||
ast::StmtNode::Block(statements) => self.on_block(environment, statements),
|
ast::StmtNode::Block(statements) => self.on_block(es, statements),
|
||||||
ast::StmtNode::If {
|
ast::StmtNode::If {
|
||||||
condition,
|
condition,
|
||||||
then_branch,
|
then_branch,
|
||||||
else_branch,
|
else_branch,
|
||||||
} => self.on_if_statement(environment, condition, then_branch, else_branch),
|
} => self.on_if_statement(es, condition, then_branch, else_branch),
|
||||||
ast::StmtNode::Loop {
|
ast::StmtNode::Loop {
|
||||||
label,
|
label,
|
||||||
condition,
|
condition,
|
||||||
body,
|
body,
|
||||||
after_body,
|
after_body,
|
||||||
} => self.on_loop_statement(environment, label, condition, body, after_body),
|
} => self.on_loop_statement(es, label, condition, body, after_body),
|
||||||
ast::StmtNode::LoopControl {
|
ast::StmtNode::LoopControl {
|
||||||
is_break,
|
is_break,
|
||||||
loop_name,
|
loop_name,
|
||||||
} => self.on_loop_control_statemement(*is_break, loop_name),
|
} => self.on_loop_control_statemement(*is_break, loop_name),
|
||||||
ast::StmtNode::Return { token: _, value } => {
|
ast::StmtNode::Return { token: _, value } => {
|
||||||
self.on_return_statement(environment, value)
|
self.on_return_statement(es, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,8 +138,8 @@ impl Interpretable for ast::StmtNode {
|
||||||
|
|
||||||
impl ast::StmtNode {
|
impl ast::StmtNode {
|
||||||
/// Handle the `print` statement.
|
/// Handle the `print` statement.
|
||||||
fn on_print(&self, environment: &EnvironmentRef, expr: &ast::ExprNode) -> InterpreterResult {
|
fn on_print(&self, es: &mut InterpreterState, expr: &ast::ExprNode) -> InterpreterResult {
|
||||||
let value = expr.interpret(environment)?.result();
|
let value = expr.interpret(es)?.result();
|
||||||
let output = match value {
|
let output = match value {
|
||||||
Value::Nil => String::from("nil"),
|
Value::Nil => String::from("nil"),
|
||||||
Value::Boolean(true) => String::from("true"),
|
Value::Boolean(true) => String::from("true"),
|
||||||
|
@ -142,38 +155,42 @@ impl ast::StmtNode {
|
||||||
/// Handle a variable declaration.
|
/// Handle a variable declaration.
|
||||||
fn on_var_decl(
|
fn on_var_decl(
|
||||||
&self,
|
&self,
|
||||||
environment: &EnvironmentRef,
|
es: &mut InterpreterState,
|
||||||
name: &Token,
|
name: &Token,
|
||||||
initializer: &Option<ast::ExprNode>,
|
initializer: &Option<ast::ExprNode>,
|
||||||
) -> InterpreterResult {
|
) -> InterpreterResult {
|
||||||
let variable = match initializer {
|
let variable = match initializer {
|
||||||
Some(expr) => Some(expr.interpret(environment)?.result()),
|
Some(expr) => Some(expr.interpret(es)?.result()),
|
||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
environment.borrow_mut().define(name, variable)?;
|
es.environment.borrow_mut().define(name, variable)?;
|
||||||
Ok(InterpreterFlowControl::default())
|
Ok(InterpreterFlowControl::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handle a function declaration.
|
/// Handle a function declaration.
|
||||||
fn on_fun_decl(
|
fn on_fun_decl(
|
||||||
&self,
|
&self,
|
||||||
environment: &EnvironmentRef,
|
es: &mut InterpreterState,
|
||||||
name: &Token,
|
name: &Token,
|
||||||
params: &[Token],
|
params: &[Token],
|
||||||
body: &[ast::StmtNode],
|
body: &[ast::StmtNode],
|
||||||
) -> InterpreterResult {
|
) -> InterpreterResult {
|
||||||
let fun = Function::new(Some(name), params, body);
|
let fun = Function::new(Some(name), params, body);
|
||||||
environment
|
es.environment
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.define(name, Some(Value::Callable(fun)))?;
|
.define(name, Some(Value::Callable(fun)))?;
|
||||||
Ok(InterpreterFlowControl::default())
|
Ok(InterpreterFlowControl::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Execute the contents of a block.
|
/// Execute the contents of a block.
|
||||||
fn on_block(&self, environment: &EnvironmentRef, stmts: &[ast::StmtNode]) -> InterpreterResult {
|
fn on_block(&self, es: &mut InterpreterState, stmts: &[ast::StmtNode]) -> InterpreterResult {
|
||||||
let child = Environment::create_child(environment);
|
let mut child = InterpreterState{
|
||||||
|
environment: Environment::create_child(&es.environment),
|
||||||
|
globals: es.globals.clone(),
|
||||||
|
variables: es.variables,
|
||||||
|
};
|
||||||
for stmt in stmts.iter() {
|
for stmt in stmts.iter() {
|
||||||
let result = stmt.interpret(&child)?;
|
let result = stmt.interpret(&mut child)?;
|
||||||
if result.is_flow_control() {
|
if result.is_flow_control() {
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
@ -184,15 +201,15 @@ impl ast::StmtNode {
|
||||||
/// Execute an if statement.
|
/// Execute an if statement.
|
||||||
fn on_if_statement(
|
fn on_if_statement(
|
||||||
&self,
|
&self,
|
||||||
environment: &EnvironmentRef,
|
es: &mut InterpreterState,
|
||||||
condition: &ast::ExprNode,
|
condition: &ast::ExprNode,
|
||||||
then_branch: &ast::StmtNode,
|
then_branch: &ast::StmtNode,
|
||||||
else_branch: &Option<Box<ast::StmtNode>>,
|
else_branch: &Option<Box<ast::StmtNode>>,
|
||||||
) -> InterpreterResult {
|
) -> InterpreterResult {
|
||||||
if condition.interpret(environment)?.result().is_truthy() {
|
if condition.interpret(es)?.result().is_truthy() {
|
||||||
then_branch.interpret(environment)
|
then_branch.interpret(es)
|
||||||
} else if let Some(else_stmt) = else_branch {
|
} else if let Some(else_stmt) = else_branch {
|
||||||
else_stmt.interpret(environment)
|
else_stmt.interpret(es)
|
||||||
} else {
|
} else {
|
||||||
Ok(InterpreterFlowControl::default())
|
Ok(InterpreterFlowControl::default())
|
||||||
}
|
}
|
||||||
|
@ -201,15 +218,15 @@ impl ast::StmtNode {
|
||||||
/// Execute a while statement.
|
/// Execute a while statement.
|
||||||
fn on_loop_statement(
|
fn on_loop_statement(
|
||||||
&self,
|
&self,
|
||||||
environment: &EnvironmentRef,
|
es: &mut InterpreterState,
|
||||||
label: &Option<Token>,
|
label: &Option<Token>,
|
||||||
condition: &ast::ExprNode,
|
condition: &ast::ExprNode,
|
||||||
body: &ast::StmtNode,
|
body: &ast::StmtNode,
|
||||||
after_body: &Option<Box<ast::StmtNode>>,
|
after_body: &Option<Box<ast::StmtNode>>,
|
||||||
) -> InterpreterResult {
|
) -> InterpreterResult {
|
||||||
let ln = label.as_ref().map(|token| token.lexeme.clone());
|
let ln = label.as_ref().map(|token| token.lexeme.clone());
|
||||||
while condition.interpret(environment)?.result().is_truthy() {
|
while condition.interpret(es)?.result().is_truthy() {
|
||||||
let result = body.interpret(environment)?;
|
let result = body.interpret(es)?;
|
||||||
match &result {
|
match &result {
|
||||||
InterpreterFlowControl::Result(_) => (),
|
InterpreterFlowControl::Result(_) => (),
|
||||||
InterpreterFlowControl::Continue(lv) if lv == &ln => (),
|
InterpreterFlowControl::Continue(lv) if lv == &ln => (),
|
||||||
|
@ -217,7 +234,7 @@ impl ast::StmtNode {
|
||||||
_ => return Ok(result),
|
_ => return Ok(result),
|
||||||
}
|
}
|
||||||
if let Some(stmt) = after_body {
|
if let Some(stmt) = after_body {
|
||||||
let result = stmt.interpret(environment)?;
|
let result = stmt.interpret(es)?;
|
||||||
match &result {
|
match &result {
|
||||||
InterpreterFlowControl::Result(_) => (),
|
InterpreterFlowControl::Result(_) => (),
|
||||||
InterpreterFlowControl::Continue(lv) if lv == &ln => (),
|
InterpreterFlowControl::Continue(lv) if lv == &ln => (),
|
||||||
|
@ -246,12 +263,12 @@ impl ast::StmtNode {
|
||||||
/// Execute a return statement.
|
/// Execute a return statement.
|
||||||
fn on_return_statement(
|
fn on_return_statement(
|
||||||
&self,
|
&self,
|
||||||
environment: &EnvironmentRef,
|
es: &mut InterpreterState,
|
||||||
value: &Option<ast::ExprNode>,
|
value: &Option<ast::ExprNode>,
|
||||||
) -> InterpreterResult {
|
) -> InterpreterResult {
|
||||||
let rv = match value {
|
let rv = match value {
|
||||||
None => Value::Nil,
|
None => Value::Nil,
|
||||||
Some(expr) => expr.interpret(environment)?.result(),
|
Some(expr) => expr.interpret(es)?.result(),
|
||||||
};
|
};
|
||||||
Ok(InterpreterFlowControl::Return(rv))
|
Ok(InterpreterFlowControl::Return(rv))
|
||||||
}
|
}
|
||||||
|
@ -262,32 +279,32 @@ impl ast::StmtNode {
|
||||||
* -------------------------------- */
|
* -------------------------------- */
|
||||||
|
|
||||||
impl Interpretable for ast::ExprNode {
|
impl Interpretable for ast::ExprNode {
|
||||||
fn interpret(&self, environment: &EnvironmentRef) -> InterpreterResult {
|
fn interpret(&self, es: &mut InterpreterState) -> InterpreterResult {
|
||||||
match self {
|
match self {
|
||||||
ast::ExprNode::Assignment { name, value } => {
|
ast::ExprNode::Assignment { name, value } => {
|
||||||
let value = value.interpret(environment)?.result();
|
let value = value.interpret(es)?.result();
|
||||||
environment.borrow_mut().assign(name, value)?;
|
es.environment.borrow_mut().assign(name, value)?;
|
||||||
Ok(InterpreterFlowControl::default())
|
Ok(InterpreterFlowControl::default())
|
||||||
}
|
}
|
||||||
ast::ExprNode::Logical {
|
ast::ExprNode::Logical {
|
||||||
left,
|
left,
|
||||||
operator,
|
operator,
|
||||||
right,
|
right,
|
||||||
} => self.on_logic(environment, left, operator, right),
|
} => self.on_logic(es, left, operator, right),
|
||||||
ast::ExprNode::Binary {
|
ast::ExprNode::Binary {
|
||||||
left,
|
left,
|
||||||
operator,
|
operator,
|
||||||
right,
|
right,
|
||||||
} => self.on_binary(environment, left, operator, right),
|
} => self.on_binary(es, left, operator, right),
|
||||||
ast::ExprNode::Unary { operator, right } => self.on_unary(environment, operator, right),
|
ast::ExprNode::Unary { operator, right } => self.on_unary(es, operator, right),
|
||||||
ast::ExprNode::Grouping { expression } => expression.interpret(environment),
|
ast::ExprNode::Grouping { expression } => expression.interpret(es),
|
||||||
ast::ExprNode::Litteral { value } => self.on_litteral(value),
|
ast::ExprNode::Litteral { value } => self.on_litteral(value),
|
||||||
ast::ExprNode::Variable { name } => Ok(environment.borrow().get(name)?.into()),
|
ast::ExprNode::Variable { name } => Ok(es.environment.borrow().get(name)?.into()),
|
||||||
ast::ExprNode::Call {
|
ast::ExprNode::Call {
|
||||||
callee,
|
callee,
|
||||||
right_paren,
|
right_paren,
|
||||||
arguments,
|
arguments,
|
||||||
} => self.on_call(environment, callee, right_paren, arguments),
|
} => self.on_call(es, callee, right_paren, arguments),
|
||||||
ast::ExprNode::Lambda { params, body } => {
|
ast::ExprNode::Lambda { params, body } => {
|
||||||
Ok(Value::Callable(Function::new(None, params, body)).into())
|
Ok(Value::Callable(Function::new(None, params, body)).into())
|
||||||
}
|
}
|
||||||
|
@ -299,31 +316,31 @@ impl ast::ExprNode {
|
||||||
/// Evaluate a logical operator.
|
/// Evaluate a logical operator.
|
||||||
fn on_logic(
|
fn on_logic(
|
||||||
&self,
|
&self,
|
||||||
environment: &EnvironmentRef,
|
es: &mut InterpreterState,
|
||||||
left: &ast::ExprNode,
|
left: &ast::ExprNode,
|
||||||
operator: &Token,
|
operator: &Token,
|
||||||
right: &ast::ExprNode,
|
right: &ast::ExprNode,
|
||||||
) -> InterpreterResult {
|
) -> InterpreterResult {
|
||||||
let left_value = left.interpret(environment)?.result();
|
let left_value = left.interpret(es)?.result();
|
||||||
if operator.token_type == TokenType::Or && left_value.is_truthy()
|
if operator.token_type == TokenType::Or && left_value.is_truthy()
|
||||||
|| operator.token_type == TokenType::And && !left_value.is_truthy()
|
|| operator.token_type == TokenType::And && !left_value.is_truthy()
|
||||||
{
|
{
|
||||||
Ok(left_value.into())
|
Ok(left_value.into())
|
||||||
} else {
|
} else {
|
||||||
right.interpret(environment)
|
right.interpret(es)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate a binary operator.
|
/// Evaluate a binary operator.
|
||||||
fn on_binary(
|
fn on_binary(
|
||||||
&self,
|
&self,
|
||||||
environment: &EnvironmentRef,
|
es: &mut InterpreterState,
|
||||||
left: &ast::ExprNode,
|
left: &ast::ExprNode,
|
||||||
operator: &Token,
|
operator: &Token,
|
||||||
right: &ast::ExprNode,
|
right: &ast::ExprNode,
|
||||||
) -> InterpreterResult {
|
) -> InterpreterResult {
|
||||||
let left_value = left.interpret(environment)?.result();
|
let left_value = left.interpret(es)?.result();
|
||||||
let right_value = right.interpret(environment)?.result();
|
let right_value = right.interpret(es)?.result();
|
||||||
match operator.token_type {
|
match operator.token_type {
|
||||||
TokenType::Plus => match (left_value, right_value) {
|
TokenType::Plus => match (left_value, right_value) {
|
||||||
(Value::Number(a), Value::Number(b)) => Ok(Value::Number(a + b).into()),
|
(Value::Number(a), Value::Number(b)) => Ok(Value::Number(a + b).into()),
|
||||||
|
@ -388,11 +405,11 @@ impl ast::ExprNode {
|
||||||
/// Evaluate an unary operator.
|
/// Evaluate an unary operator.
|
||||||
fn on_unary(
|
fn on_unary(
|
||||||
&self,
|
&self,
|
||||||
environment: &EnvironmentRef,
|
es: &mut InterpreterState,
|
||||||
operator: &Token,
|
operator: &Token,
|
||||||
right: &ast::ExprNode,
|
right: &ast::ExprNode,
|
||||||
) -> InterpreterResult {
|
) -> InterpreterResult {
|
||||||
let right_value = right.interpret(environment)?.result();
|
let right_value = right.interpret(es)?.result();
|
||||||
match operator.token_type {
|
match operator.token_type {
|
||||||
TokenType::Minus => {
|
TokenType::Minus => {
|
||||||
if let Value::Number(n) = right_value {
|
if let Value::Number(n) = right_value {
|
||||||
|
@ -427,16 +444,16 @@ impl ast::ExprNode {
|
||||||
/// Evaluate a function call.
|
/// Evaluate a function call.
|
||||||
fn on_call(
|
fn on_call(
|
||||||
&self,
|
&self,
|
||||||
environment: &EnvironmentRef,
|
es: &mut InterpreterState,
|
||||||
callee: &ast::ExprNode,
|
callee: &ast::ExprNode,
|
||||||
right_paren: &Token,
|
right_paren: &Token,
|
||||||
arguments: &Vec<ast::ExprNode>,
|
arguments: &Vec<ast::ExprNode>,
|
||||||
) -> InterpreterResult {
|
) -> InterpreterResult {
|
||||||
let callee = callee.interpret(environment)?.result();
|
let callee = callee.interpret(es)?.result();
|
||||||
let arg_values = {
|
let arg_values = {
|
||||||
let mut v = Vec::with_capacity(arguments.len());
|
let mut v = Vec::with_capacity(arguments.len());
|
||||||
for argument in arguments.iter() {
|
for argument in arguments.iter() {
|
||||||
v.push(argument.interpret(environment)?.result());
|
v.push(argument.interpret(es)?.result());
|
||||||
}
|
}
|
||||||
v
|
v
|
||||||
};
|
};
|
||||||
|
@ -453,7 +470,7 @@ impl ast::ExprNode {
|
||||||
),
|
),
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
Ok(callable.call(environment, arg_values)?.into())
|
Ok(callable.call(es, arg_values)?.into())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
error(right_paren, "can only call functions and classes")
|
error(right_paren, "can only call functions and classes")
|
||||||
|
|
|
@ -5,7 +5,7 @@ mod interpretable;
|
||||||
mod native_fn;
|
mod native_fn;
|
||||||
mod value;
|
mod value;
|
||||||
|
|
||||||
pub use callable::{Callable, CallableRef};
|
pub(self) use callable::{Callable, CallableRef};
|
||||||
pub use environment::*;
|
pub(self) use environment::*;
|
||||||
pub use interpretable::*;
|
pub use interpretable::*;
|
||||||
pub use value::*;
|
pub use value::*;
|
||||||
|
|
|
@ -6,7 +6,7 @@ use std::{
|
||||||
|
|
||||||
use crate::errors::SloxResult;
|
use crate::errors::SloxResult;
|
||||||
|
|
||||||
use super::{Callable, CallableRef, EnvironmentRef, Value};
|
use super::{Callable, CallableRef, InterpreterState, Value};
|
||||||
|
|
||||||
/* ----------- *
|
/* ----------- *
|
||||||
* clock() *
|
* clock() *
|
||||||
|
@ -20,7 +20,7 @@ impl Callable for Clock {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(&self, _environment: &EnvironmentRef, _arguments: Vec<Value>) -> SloxResult<Value> {
|
fn call(&self, _environment: &mut InterpreterState, _arguments: Vec<Value>) -> SloxResult<Value> {
|
||||||
let now = SystemTime::now();
|
let now = SystemTime::now();
|
||||||
let since_epoch = now
|
let since_epoch = now
|
||||||
.duration_since(UNIX_EPOCH)
|
.duration_since(UNIX_EPOCH)
|
||||||
|
@ -35,6 +35,6 @@ impl ToString for Clock {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn clock() -> CallableRef {
|
pub(super) fn clock() -> CallableRef {
|
||||||
Rc::new(RefCell::new(Clock {}))
|
Rc::new(RefCell::new(Clock {}))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue