Interpreter - Refactored internals out of the node implemntations

This commit is contained in:
Emmanuel BENOîT 2023-01-17 07:23:17 +01:00
parent b01ae10d09
commit 18d9bfb74c

View file

@ -1,7 +1,10 @@
use std::{cell::RefCell, collections::HashMap, rc::Rc}; use std::{cell::RefCell, collections::HashMap, rc::Rc};
use crate::{ use crate::{
ast::{ClassDecl, ExprNode, FunDecl, GetExpr, ProgramNode, SetExpr, StmtNode, VariableExpr}, ast::{
ClassDecl, ExprNode, FunDecl, GetExpr, ProgramNode, SetExpr, StmtNode, SuperExpr,
VariableExpr,
},
errors::{ErrorKind, SloxError, SloxResult}, errors::{ErrorKind, SloxError, SloxResult},
resolver::ResolvedVariables, resolver::ResolvedVariables,
tokens::{Token, TokenType}, tokens::{Token, TokenType},
@ -128,9 +131,9 @@ fn error<T>(token: &Token, message: &str) -> SloxResult<T> {
)) ))
} }
/* ----------------------------- * /* -------------------------- *
* INTERPRETER FOR PROGRAM NODES * * ENTRY POINTS FOR AST NODES *
* ----------------------------- */ * -------------------------- */
impl Interpretable for ProgramNode { impl Interpretable for ProgramNode {
fn interpret(&self, es: &mut InterpreterState) -> InterpreterResult { fn interpret(&self, es: &mut InterpreterState) -> InterpreterResult {
@ -141,39 +144,85 @@ impl Interpretable for ProgramNode {
} }
} }
/* ------------------------------- *
* INTERPRETER FOR STATEMENT NODES *
* ------------------------------- */
impl Interpretable for StmtNode { impl Interpretable for StmtNode {
fn interpret(&self, es: &mut InterpreterState) -> InterpreterResult { fn interpret(&self, es: &mut InterpreterState) -> InterpreterResult {
match self { match self {
StmtNode::VarDecl(name, expr) => self.on_var_decl(es, name, expr), StmtNode::VarDecl(name, expr) => on_var_decl(es, name, expr),
StmtNode::FunDecl(decl) => self.on_fun_decl(es, decl), StmtNode::FunDecl(decl) => on_fun_decl(es, decl),
StmtNode::ClassDecl(decl) => self.on_class_decl(es, decl), StmtNode::ClassDecl(decl) => on_class_decl(es, decl),
StmtNode::Expression(expr) => expr.interpret(es), StmtNode::Expression(expr) => expr.interpret(es),
StmtNode::Print(expr) => self.on_print(es, expr), StmtNode::Print(expr) => on_print(es, expr),
StmtNode::Block(statements) => self.on_block(es, statements), StmtNode::Block(statements) => on_block(es, statements),
StmtNode::If { StmtNode::If {
condition, condition,
then_branch, then_branch,
else_branch, else_branch,
} => self.on_if_statement(es, condition, then_branch, else_branch), } => on_if_statement(es, condition, then_branch, else_branch),
StmtNode::Loop { StmtNode::Loop {
label, label,
condition, condition,
body, body,
after_body, after_body,
} => self.on_loop_statement(es, label, condition, body, after_body), } => on_loop_statement(es, label, condition, body, after_body),
StmtNode::LoopControl { StmtNode::LoopControl {
is_break, is_break,
loop_name, loop_name,
} => self.on_loop_control_statemement(*is_break, loop_name), } => on_loop_control_statemement(*is_break, loop_name),
StmtNode::Return { token: _, value } => self.on_return_statement(es, value), StmtNode::Return { token: _, value } => on_return_statement(es, value),
} }
} }
} }
impl Interpretable for ExprNode {
fn interpret(&self, es: &mut InterpreterState) -> InterpreterResult {
match self {
ExprNode::Assignment { name, value, id } => {
let value = value.interpret(es)?.result();
es.assign_var(name, id, value)?;
Ok(InterpreterFlowControl::default())
}
ExprNode::Logical(binary_expr) => on_logic(
es,
&binary_expr.left,
&binary_expr.operator,
&binary_expr.right,
),
ExprNode::Binary(binary_expr) => on_binary(
es,
&binary_expr.left,
&binary_expr.operator,
&binary_expr.right,
),
ExprNode::Unary { operator, right } => on_unary(es, operator, right),
ExprNode::Grouping { expression } => expression.interpret(es),
ExprNode::Litteral { value } => on_litteral(value),
ExprNode::Variable(var_expr) | ExprNode::This(var_expr) => var_expr.interpret(es),
ExprNode::Call {
callee,
right_paren,
arguments,
} => on_call(es, callee, right_paren, arguments),
ExprNode::Lambda { params, body } => {
let lambda = Function::new(None, params, body, es.environment.clone(), false);
Ok(Value::from(lambda).into())
}
ExprNode::Get(get_expr) => on_get_expression(es, get_expr),
ExprNode::Set(set_expr) => on_set_expression(es, set_expr),
ExprNode::Super(super_expr) => on_super(es, super_expr),
}
}
}
impl Interpretable for VariableExpr {
fn interpret(&self, es: &mut InterpreterState) -> InterpreterResult {
Ok(es.lookup_var(self)?.into())
}
}
/* --------------------- *
* INTERPRETER INTERNALS *
* --------------------- */
/// Extract members from a class declaration, generating a map of /// Extract members from a class declaration, generating a map of
/// functions. /// functions.
fn extract_members( fn extract_members(
@ -198,425 +247,345 @@ fn extract_members(
.collect() .collect()
} }
impl StmtNode { /// Handle the `print` statement.
/// Handle the `print` statement. fn on_print(es: &mut InterpreterState, expr: &ExprNode) -> InterpreterResult {
fn on_print(&self, es: &mut InterpreterState, expr: &ExprNode) -> InterpreterResult { let value = expr.interpret(es)?.result();
let value = expr.interpret(es)?.result(); let output = value.to_string();
let output = value.to_string(); println!("{}", output);
println!("{}", output); Ok(InterpreterFlowControl::default())
Ok(InterpreterFlowControl::default()) }
}
/// Handle a variable declaration. /// Handle a variable declaration.
fn on_var_decl( fn on_var_decl(
&self, es: &mut InterpreterState,
es: &mut InterpreterState, name: &Token,
name: &Token, initializer: &Option<ExprNode>,
initializer: &Option<ExprNode>, ) -> InterpreterResult {
) -> InterpreterResult { let variable = match initializer {
let variable = match initializer { Some(expr) => Some(expr.interpret(es)?.result()),
Some(expr) => Some(expr.interpret(es)?.result()), None => None,
None => None, };
}; es.environment.borrow_mut().define(name, variable)?;
es.environment.borrow_mut().define(name, variable)?; Ok(InterpreterFlowControl::default())
Ok(InterpreterFlowControl::default()) }
}
/// Handle a class declaration /// Handle a class declaration
fn on_class_decl(&self, es: &mut InterpreterState, decl: &ClassDecl) -> InterpreterResult { fn on_class_decl(es: &mut InterpreterState, decl: &ClassDecl) -> InterpreterResult {
es.environment.borrow_mut().define(&decl.name, None)?; es.environment.borrow_mut().define(&decl.name, None)?;
let class = match &decl.superclass { let class = match &decl.superclass {
None => Class::new(decl.name.lexeme.clone(), None, extract_members(es, decl)), None => Class::new(decl.name.lexeme.clone(), None, extract_members(es, decl)),
Some(superclass) => { Some(superclass) => {
let sc_value = superclass.interpret(es)?.result(); let sc_value = superclass.interpret(es)?.result();
let sc_ref = if let Some(sc_ref) = sc_value.as_class_ref() { let sc_ref = if let Some(sc_ref) = sc_value.as_class_ref() {
Some(sc_ref) Some(sc_ref)
} else { } else {
return error(&superclass.token, "superclass must be a class"); return error(&superclass.token, "superclass must be a class");
}; };
let mut sub_env = InterpreterState::create_child(es); let mut sub_env = InterpreterState::create_child(es);
sub_env sub_env
.environment .environment
.borrow_mut() .borrow_mut()
.set("super", sc_value.clone()); .set("super", sc_value.clone());
Class::new( Class::new(
decl.name.lexeme.clone(), decl.name.lexeme.clone(),
sc_ref, sc_ref,
extract_members(&mut sub_env, decl), extract_members(&mut sub_env, decl),
) )
}
};
es.environment
.borrow_mut()
.assign(&decl.name, class.into())?;
Ok(InterpreterFlowControl::default())
}
/// Handle a function declaration.
fn on_fun_decl(&self, es: &mut InterpreterState, decl: &FunDecl) -> InterpreterResult {
let fun = Function::new(
Some(&decl.name),
&decl.params,
&decl.body,
es.environment.clone(),
false,
);
es.environment
.borrow_mut()
.define(&decl.name, Some(fun.into()))?;
Ok(InterpreterFlowControl::default())
}
/// Execute the contents of a block.
fn on_block(&self, es: &mut InterpreterState, stmts: &[StmtNode]) -> InterpreterResult {
let mut child = InterpreterState::create_child(es);
for stmt in stmts.iter() {
let result = stmt.interpret(&mut child)?;
if result.is_flow_control() {
return Ok(result);
}
} }
Ok(InterpreterFlowControl::default()) };
} es.environment
.borrow_mut()
.assign(&decl.name, class.into())?;
Ok(InterpreterFlowControl::default())
}
/// Execute an if statement. /// Handle a function declaration.
fn on_if_statement( fn on_fun_decl(es: &mut InterpreterState, decl: &FunDecl) -> InterpreterResult {
&self, let fun = Function::new(
es: &mut InterpreterState, Some(&decl.name),
condition: &ExprNode, &decl.params,
then_branch: &StmtNode, &decl.body,
else_branch: &Option<Box<StmtNode>>, es.environment.clone(),
) -> InterpreterResult { false,
if condition.interpret(es)?.result().is_truthy() { );
then_branch.interpret(es) es.environment
} else if let Some(else_stmt) = else_branch { .borrow_mut()
else_stmt.interpret(es) .define(&decl.name, Some(fun.into()))?;
} else { Ok(InterpreterFlowControl::default())
Ok(InterpreterFlowControl::default()) }
/// Execute the contents of a block.
fn on_block(es: &mut InterpreterState, stmts: &[StmtNode]) -> InterpreterResult {
let mut child = InterpreterState::create_child(es);
for stmt in stmts.iter() {
let result = stmt.interpret(&mut child)?;
if result.is_flow_control() {
return Ok(result);
} }
} }
Ok(InterpreterFlowControl::default())
}
/// Execute a while statement. /// Execute an if statement.
fn on_loop_statement( fn on_if_statement(
&self, es: &mut InterpreterState,
es: &mut InterpreterState, condition: &ExprNode,
label: &Option<Token>, then_branch: &StmtNode,
condition: &ExprNode, else_branch: &Option<Box<StmtNode>>,
body: &StmtNode, ) -> InterpreterResult {
after_body: &Option<Box<StmtNode>>, if condition.interpret(es)?.result().is_truthy() {
) -> InterpreterResult { then_branch.interpret(es)
let ln = label.as_ref().map(|token| token.lexeme.clone()); } else if let Some(else_stmt) = else_branch {
while condition.interpret(es)?.result().is_truthy() { else_stmt.interpret(es)
let result = body.interpret(es)?; } else {
Ok(InterpreterFlowControl::default())
}
}
/// Execute a while statement.
fn on_loop_statement(
es: &mut InterpreterState,
label: &Option<Token>,
condition: &ExprNode,
body: &StmtNode,
after_body: &Option<Box<StmtNode>>,
) -> InterpreterResult {
let ln = label.as_ref().map(|token| token.lexeme.clone());
while condition.interpret(es)?.result().is_truthy() {
let result = body.interpret(es)?;
match &result {
InterpreterFlowControl::Result(_) => (),
InterpreterFlowControl::Continue(lv) if lv == &ln => (),
InterpreterFlowControl::Break(lv) if lv == &ln => break,
_ => return Ok(result),
}
if let Some(stmt) = after_body {
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 => (),
InterpreterFlowControl::Break(lv) if lv == &ln => break, InterpreterFlowControl::Break(lv) if lv == &ln => break,
_ => return Ok(result), _ => return Ok(result),
} }
if let Some(stmt) = after_body {
let result = stmt.interpret(es)?;
match &result {
InterpreterFlowControl::Result(_) => (),
InterpreterFlowControl::Continue(lv) if lv == &ln => (),
InterpreterFlowControl::Break(lv) if lv == &ln => break,
_ => return Ok(result),
}
}
}
Ok(InterpreterFlowControl::default())
}
/// Execute a loop control statement.
fn on_loop_control_statemement(
&self,
is_break: bool,
label: &Option<Token>,
) -> InterpreterResult {
let name = label.as_ref().map(|token| token.lexeme.clone());
if is_break {
Ok(InterpreterFlowControl::Break(name))
} else {
Ok(InterpreterFlowControl::Continue(name))
} }
} }
Ok(InterpreterFlowControl::default())
}
/// Execute a return statement. /// Execute a loop control statement.
fn on_return_statement( fn on_loop_control_statemement(is_break: bool, label: &Option<Token>) -> InterpreterResult {
&self, let name = label.as_ref().map(|token| token.lexeme.clone());
es: &mut InterpreterState, if is_break {
value: &Option<ExprNode>, Ok(InterpreterFlowControl::Break(name))
) -> InterpreterResult { } else {
let rv = match value { Ok(InterpreterFlowControl::Continue(name))
None => Value::Nil,
Some(expr) => expr.interpret(es)?.result(),
};
Ok(InterpreterFlowControl::Return(rv))
} }
} }
/* -------------------------------- * /// Execute a return statement.
* INTERPRETER FOR EXPRESSION NODES * fn on_return_statement(es: &mut InterpreterState, value: &Option<ExprNode>) -> InterpreterResult {
* -------------------------------- */ let rv = match value {
None => Value::Nil,
Some(expr) => expr.interpret(es)?.result(),
};
Ok(InterpreterFlowControl::Return(rv))
}
impl Interpretable for ExprNode { /// Evaluate a logical operator.
fn interpret(&self, es: &mut InterpreterState) -> InterpreterResult { fn on_logic(
match self { es: &mut InterpreterState,
ExprNode::Assignment { name, value, id } => { left: &ExprNode,
let value = value.interpret(es)?.result(); operator: &Token,
es.assign_var(name, id, value)?; right: &ExprNode,
Ok(InterpreterFlowControl::default()) ) -> InterpreterResult {
} let left_value = left.interpret(es)?.result();
ExprNode::Logical(binary_expr) => self.on_logic( if operator.token_type == TokenType::Or && left_value.is_truthy()
es, || operator.token_type == TokenType::And && !left_value.is_truthy()
&binary_expr.left, {
&binary_expr.operator, Ok(left_value.into())
&binary_expr.right, } else {
), right.interpret(es)
ExprNode::Binary(binary_expr) => self.on_binary(
es,
&binary_expr.left,
&binary_expr.operator,
&binary_expr.right,
),
ExprNode::Unary { operator, right } => self.on_unary(es, operator, right),
ExprNode::Grouping { expression } => expression.interpret(es),
ExprNode::Litteral { value } => self.on_litteral(value),
ExprNode::Variable(var_expr) | ExprNode::This(var_expr) => var_expr.interpret(es),
ExprNode::Call {
callee,
right_paren,
arguments,
} => self.on_call(es, callee, right_paren, arguments),
ExprNode::Lambda { params, body } => {
let lambda = Function::new(None, params, body, es.environment.clone(), false);
Ok(Value::from(lambda).into())
}
ExprNode::Get(get_expr) => self.on_get_expression(es, get_expr),
ExprNode::Set(set_expr) => self.on_set_expression(es, set_expr),
ExprNode::Super(super_expr) => {
let distance = match es.locals.get(&super_expr.keyword.id) {
Some(distance) => *distance,
None => panic!("super environment not found"),
};
assert!(distance > 0);
let obj_ref = es.environment.borrow().get_at(
distance - 1,
&Token {
token_type: TokenType::This,
lexeme: "this".to_owned(),
line: 0,
},
)?;
Ok(obj_ref
.with_property_carrier(
|inst| inst.get_super(es, &super_expr, distance),
|| panic!("'this' didn't contain an instance"),
)?
.into())
}
}
} }
} }
impl Interpretable for VariableExpr { /// Evaluate a binary operator.
fn interpret(&self, es: &mut InterpreterState) -> InterpreterResult { fn on_binary(
Ok(es.lookup_var(self)?.into()) es: &mut InterpreterState,
} left: &ExprNode,
} operator: &Token,
right: &ExprNode,
) -> InterpreterResult {
let left_value = left.interpret(es)?.result();
let right_value = right.interpret(es)?.result();
match operator.token_type {
TokenType::Plus => match (left_value, right_value) {
(Value::Number(a), Value::Number(b)) => Ok(Value::Number(a + b).into()),
(Value::String(a), Value::String(b)) => Ok(Value::String(a + &b).into()),
_ => error(operator, "type error"),
},
impl ExprNode { TokenType::Minus => match (left_value, right_value) {
/// Evaluate a logical operator. (Value::Number(a), Value::Number(b)) => Ok(Value::Number(a - b).into()),
fn on_logic( _ => error(operator, "type error"),
&self, },
es: &mut InterpreterState,
left: &ExprNode,
operator: &Token,
right: &ExprNode,
) -> InterpreterResult {
let left_value = left.interpret(es)?.result();
if operator.token_type == TokenType::Or && left_value.is_truthy()
|| operator.token_type == TokenType::And && !left_value.is_truthy()
{
Ok(left_value.into())
} else {
right.interpret(es)
}
}
/// Evaluate a binary operator. TokenType::Star => match (left_value, right_value) {
fn on_binary( (Value::Number(a), Value::Number(b)) => Ok(Value::Number(a * b).into()),
&self, (Value::String(a), Value::Number(b)) => Ok(Value::String(a.repeat(b as usize)).into()),
es: &mut InterpreterState, _ => error(operator, "type error"),
left: &ExprNode, },
operator: &Token,
right: &ExprNode,
) -> InterpreterResult {
let left_value = left.interpret(es)?.result();
let right_value = right.interpret(es)?.result();
match operator.token_type {
TokenType::Plus => match (left_value, right_value) {
(Value::Number(a), Value::Number(b)) => Ok(Value::Number(a + b).into()),
(Value::String(a), Value::String(b)) => Ok(Value::String(a + &b).into()),
_ => error(operator, "type error"),
},
TokenType::Minus => match (left_value, right_value) { TokenType::Slash => match (left_value, right_value) {
(Value::Number(a), Value::Number(b)) => Ok(Value::Number(a - b).into()), (Value::Number(a), Value::Number(b)) => {
_ => error(operator, "type error"), if b == 0. {
}, error(operator, "division by zero")
TokenType::Star => match (left_value, right_value) {
(Value::Number(a), Value::Number(b)) => Ok(Value::Number(a * b).into()),
(Value::String(a), Value::Number(b)) => {
Ok(Value::String(a.repeat(b as usize)).into())
}
_ => error(operator, "type error"),
},
TokenType::Slash => match (left_value, right_value) {
(Value::Number(a), Value::Number(b)) => {
if b == 0. {
error(operator, "division by zero")
} else {
Ok(Value::Number(a / b).into())
}
}
_ => error(operator, "type error"),
},
TokenType::Greater => match (left_value, right_value) {
(Value::Number(a), Value::Number(b)) => Ok(Value::Boolean(a > b).into()),
_ => error(operator, "type error"),
},
TokenType::GreaterEqual => match (left_value, right_value) {
(Value::Number(a), Value::Number(b)) => Ok(Value::Boolean(a >= b).into()),
_ => error(operator, "type error"),
},
TokenType::Less => match (left_value, right_value) {
(Value::Number(a), Value::Number(b)) => Ok(Value::Boolean(a < b).into()),
_ => error(operator, "type error"),
},
TokenType::LessEqual => match (left_value, right_value) {
(Value::Number(a), Value::Number(b)) => Ok(Value::Boolean(a <= b).into()),
_ => error(operator, "type error"),
},
TokenType::EqualEqual => Ok(Value::Boolean(left_value == right_value).into()),
TokenType::BangEqual => Ok(Value::Boolean(left_value != right_value).into()),
_ => panic!(
"Unsupported token type for binary operator (token {:?})",
operator
),
}
}
/// Evaluate an unary operator.
fn on_unary(
&self,
es: &mut InterpreterState,
operator: &Token,
right: &ExprNode,
) -> InterpreterResult {
let right_value = right.interpret(es)?.result();
match operator.token_type {
TokenType::Minus => {
if let Value::Number(n) = right_value {
Ok(Value::Number(-n).into())
} else { } else {
error(operator, "number expected") Ok(Value::Number(a / b).into())
} }
} }
_ => error(operator, "type error"),
},
TokenType::Bang => Ok(Value::Boolean(!right_value.is_truthy()).into()), TokenType::Greater => match (left_value, right_value) {
(Value::Number(a), Value::Number(b)) => Ok(Value::Boolean(a > b).into()),
_ => error(operator, "type error"),
},
_ => panic!( TokenType::GreaterEqual => match (left_value, right_value) {
"Unsupported token type for unary operator (token {:?})", (Value::Number(a), Value::Number(b)) => Ok(Value::Boolean(a >= b).into()),
operator _ => error(operator, "type error"),
), },
}
}
/// Evaluate a litteral. TokenType::Less => match (left_value, right_value) {
fn on_litteral(&self, value: &Token) -> InterpreterResult { (Value::Number(a), Value::Number(b)) => Ok(Value::Boolean(a < b).into()),
let out_value = match &value.token_type { _ => error(operator, "type error"),
TokenType::Nil => Value::Nil, },
TokenType::True => Value::Boolean(true),
TokenType::False => Value::Boolean(false),
TokenType::Number(n) => Value::Number(*n),
TokenType::String(s) => Value::String(s.clone()),
_ => panic!("Unsupported token type for litteral (token {:?})", value),
};
Ok(out_value.into())
}
/// Evaluate a function call. TokenType::LessEqual => match (left_value, right_value) {
fn on_call( (Value::Number(a), Value::Number(b)) => Ok(Value::Boolean(a <= b).into()),
&self, _ => error(operator, "type error"),
es: &mut InterpreterState, },
callee: &ExprNode,
right_paren: &Token,
arguments: &Vec<ExprNode>,
) -> InterpreterResult {
let callee = callee.interpret(es)?.result();
let arg_values = {
let mut v = Vec::with_capacity(arguments.len());
for argument in arguments.iter() {
v.push(argument.interpret(es)?.result());
}
v
};
callee.with_callable(
|callable| {
if callable.arity() != arg_values.len() {
Err(SloxError::with_token(
ErrorKind::Runtime,
right_paren,
format!(
"expected {} arguments, found {}",
arg_values.len(),
callable.arity()
),
))
} else {
Ok(callable.call(es, arg_values)?.into())
}
},
|| error(right_paren, "expression result is not callable"),
)
}
/// Evaluate a get expression. TokenType::EqualEqual => Ok(Value::Boolean(left_value == right_value).into()),
fn on_get_expression( TokenType::BangEqual => Ok(Value::Boolean(left_value != right_value).into()),
&self,
itpr_state: &mut InterpreterState,
get_expr: &GetExpr,
) -> InterpreterResult {
let instance = get_expr.instance.interpret(itpr_state)?.result();
instance.with_property_carrier(
|inst| inst.get(itpr_state, &get_expr.name).map(|v| v.into()),
|| error(&get_expr.name, "this object doesn't have properties"),
)
}
/// Evaluate a set expression. _ => panic!(
fn on_set_expression( "Unsupported token type for binary operator (token {:?})",
&self, operator
itpr_state: &mut InterpreterState, ),
set_expr: &SetExpr,
) -> InterpreterResult {
let instance = set_expr.instance.interpret(itpr_state)?.result();
instance.with_property_carrier(
|instance| {
let value = set_expr.value.interpret(itpr_state)?.result();
instance.set(itpr_state, &set_expr.name, value.clone());
Ok(value.into())
},
|| error(&set_expr.name, "this object doesn't have properties"),
)
} }
} }
/// Evaluate an unary operator.
fn on_unary(es: &mut InterpreterState, operator: &Token, right: &ExprNode) -> InterpreterResult {
let right_value = right.interpret(es)?.result();
match operator.token_type {
TokenType::Minus => {
if let Value::Number(n) = right_value {
Ok(Value::Number(-n).into())
} else {
error(operator, "number expected")
}
}
TokenType::Bang => Ok(Value::Boolean(!right_value.is_truthy()).into()),
_ => panic!(
"Unsupported token type for unary operator (token {:?})",
operator
),
}
}
/// Evaluate a litteral.
fn on_litteral(value: &Token) -> InterpreterResult {
let out_value = match &value.token_type {
TokenType::Nil => Value::Nil,
TokenType::True => Value::Boolean(true),
TokenType::False => Value::Boolean(false),
TokenType::Number(n) => Value::Number(*n),
TokenType::String(s) => Value::String(s.clone()),
_ => panic!("Unsupported token type for litteral (token {:?})", value),
};
Ok(out_value.into())
}
/// Evaluate a function call.
fn on_call(
es: &mut InterpreterState,
callee: &ExprNode,
right_paren: &Token,
arguments: &Vec<ExprNode>,
) -> InterpreterResult {
let callee = callee.interpret(es)?.result();
let arg_values = {
let mut v = Vec::with_capacity(arguments.len());
for argument in arguments.iter() {
v.push(argument.interpret(es)?.result());
}
v
};
callee.with_callable(
|callable| {
if callable.arity() != arg_values.len() {
Err(SloxError::with_token(
ErrorKind::Runtime,
right_paren,
format!(
"expected {} arguments, found {}",
arg_values.len(),
callable.arity()
),
))
} else {
Ok(callable.call(es, arg_values)?.into())
}
},
|| error(right_paren, "expression result is not callable"),
)
}
/// Evaluate a get expression.
fn on_get_expression(itpr_state: &mut InterpreterState, get_expr: &GetExpr) -> InterpreterResult {
let instance = get_expr.instance.interpret(itpr_state)?.result();
instance.with_property_carrier(
|inst| inst.get(itpr_state, &get_expr.name).map(|v| v.into()),
|| error(&get_expr.name, "this object doesn't have properties"),
)
}
/// Evaluate a set expression.
fn on_set_expression(itpr_state: &mut InterpreterState, set_expr: &SetExpr) -> InterpreterResult {
let instance = set_expr.instance.interpret(itpr_state)?.result();
instance.with_property_carrier(
|instance| {
let value = set_expr.value.interpret(itpr_state)?.result();
instance.set(itpr_state, &set_expr.name, value.clone());
Ok(value.into())
},
|| error(&set_expr.name, "this object doesn't have properties"),
)
}
/// Evaluate a reference to a superclass method.
fn on_super(itpr_state: &mut InterpreterState, super_expr: &SuperExpr) -> InterpreterResult {
let distance = match itpr_state.locals.get(&super_expr.keyword.id) {
Some(distance) => *distance,
None => panic!("super environment not found"),
};
assert!(distance > 0);
let obj_ref = itpr_state.environment.borrow().get_at(
distance - 1,
&Token {
token_type: TokenType::This,
lexeme: "this".to_owned(),
line: 0,
},
)?;
Ok(obj_ref
.with_property_carrier(
|inst| inst.get_super(itpr_state, &super_expr, distance),
|| panic!("'this' didn't contain an instance"),
)?
.into())
}