Interpreter - Refactored internals out of the node implemntations
This commit is contained in:
parent
b01ae10d09
commit
18d9bfb74c
1 changed files with 371 additions and 402 deletions
|
@ -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())
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue