forked from AbleScript/ablescript
Repair interpreter after parser changes
This commit is contained in:
parent
717d592710
commit
3bca3f88a6
328
src/interpret.rs
328
src/interpret.rs
|
@ -3,7 +3,7 @@
|
||||||
//! To interpret a piece of AbleScript code, you first need to
|
//! To interpret a piece of AbleScript code, you first need to
|
||||||
//! construct an [ExecEnv], which is responsible for storing the stack
|
//! construct an [ExecEnv], which is responsible for storing the stack
|
||||||
//! of local variable and function definitions accessible from an
|
//! of local variable and function definitions accessible from an
|
||||||
//! AbleScript snippet. You can then call [ExecEnv::eval_items] to
|
//! AbleScript snippet. You can then call [ExecEnv::eval_stmts] to
|
||||||
//! evaluate or execute any number of expressions or statements.
|
//! evaluate or execute any number of expressions or statements.
|
||||||
|
|
||||||
#[deny(missing_docs)]
|
#[deny(missing_docs)]
|
||||||
|
@ -11,12 +11,15 @@ use std::collections::HashMap;
|
||||||
use std::{
|
use std::{
|
||||||
convert::TryFrom,
|
convert::TryFrom,
|
||||||
io::{stdout, Write},
|
io::{stdout, Write},
|
||||||
|
process::exit,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use rand::random;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
ast::{Expr, Stmt, StmtKind},
|
||||||
base_55,
|
base_55,
|
||||||
error::{Error, ErrorKind},
|
error::{Error, ErrorKind},
|
||||||
parser::item::{Expr, Iden, Item, Stmt},
|
|
||||||
variables::{Functio, Value, Variable},
|
variables::{Functio, Value, Variable},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -61,12 +64,11 @@ impl ExecEnv {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate a set of Items in their own stack frame. Return the
|
/// Execute a set of Statements in their own stack frame. Return
|
||||||
/// value of the last Item evaluated, or an error if one or more
|
/// an error if one or more of the Stmts failed to evaluate, or if
|
||||||
/// of the Items failed to evaluate or if a `break` or `hopback`
|
/// a `break` or `hopback` statement occurred at the top level.
|
||||||
/// statement occurred at the top level.
|
pub fn eval_stmts(&mut self, stmts: &[Stmt]) -> Result<Value, Error> {
|
||||||
pub fn eval_items(&mut self, items: &[Item]) -> Result<Value, Error> {
|
match self.eval_stmts_hs(stmts)? {
|
||||||
match self.eval_items_hs(items)? {
|
|
||||||
HaltStatus::Value(v) => Ok(v),
|
HaltStatus::Value(v) => Ok(v),
|
||||||
HaltStatus::Break | HaltStatus::Hopback => Err(Error {
|
HaltStatus::Break | HaltStatus::Hopback => Err(Error {
|
||||||
// It's an error to issue a `break` outside of a
|
// It's an error to issue a `break` outside of a
|
||||||
|
@ -77,18 +79,18 @@ impl ExecEnv {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The same as `eval_items`, but report "break" and "hopback"
|
/// The same as `eval_stmts`, but report "break" and "hopback"
|
||||||
/// exit codes as normal conditions in a HaltStatus enum.
|
/// exit codes as normal conditions in a HaltStatus enum.
|
||||||
///
|
///
|
||||||
/// `interpret`-internal code should typically prefer this
|
/// `interpret`-internal code should typically prefer this
|
||||||
/// function over `eval_items`.
|
/// function over `eval_stmts`.
|
||||||
fn eval_items_hs(&mut self, items: &[Item]) -> Result<HaltStatus, Error> {
|
fn eval_stmts_hs(&mut self, stmts: &[Stmt]) -> Result<HaltStatus, Error> {
|
||||||
let init_depth = self.stack.len();
|
let init_depth = self.stack.len();
|
||||||
|
|
||||||
self.stack.push(Default::default());
|
self.stack.push(Default::default());
|
||||||
let mut final_result = Ok(HaltStatus::Value(Value::Nul));
|
let mut final_result = Ok(HaltStatus::Value(Value::Nul));
|
||||||
for item in items {
|
for stmt in stmts {
|
||||||
final_result = self.eval_item(item);
|
final_result = self.eval_stmt(stmt);
|
||||||
if !matches!(final_result, Ok(HaltStatus::Value(_))) {
|
if !matches!(final_result, Ok(HaltStatus::Value(_))) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -100,138 +102,180 @@ impl ExecEnv {
|
||||||
final_result
|
final_result
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate a single Item, returning its value or an error.
|
|
||||||
fn eval_item(&mut self, item: &Item) -> Result<HaltStatus, Error> {
|
|
||||||
match item {
|
|
||||||
Item::Expr(expr) => self.eval_expr(expr).map(|v| HaltStatus::Value(v)),
|
|
||||||
Item::Stmt(stmt) => self.eval_stmt(stmt),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Evaluate an Expr, returning its value or an error.
|
/// Evaluate an Expr, returning its value or an error.
|
||||||
fn eval_expr(&self, expr: &Expr) -> Result<Value, Error> {
|
fn eval_expr(&self, expr: &Expr) -> Result<Value, Error> {
|
||||||
use Expr::*;
|
use crate::ast::BinOpKind::*;
|
||||||
|
use crate::ast::ExprKind::*;
|
||||||
use Value::*;
|
use Value::*;
|
||||||
|
|
||||||
// NOTE(Alex): This block will get a whole lot cleaner once
|
Ok(match &expr.kind {
|
||||||
// Ondra's parser stuff gets merged (specifically 97fb19e).
|
BinOp { lhs, rhs, kind } => {
|
||||||
// For now, though, we've got a bunch of manually-checked
|
let lhs = self.eval_expr(&lhs)?;
|
||||||
// unreachable!()s in here which makes me sad...
|
let rhs = self.eval_expr(&rhs)?;
|
||||||
Ok(match expr {
|
match kind {
|
||||||
// Binary expressions.
|
|
||||||
Add { left, right }
|
|
||||||
| Subtract { left, right }
|
|
||||||
| Multiply { left, right }
|
|
||||||
| Divide { left, right }
|
|
||||||
| Lt { left, right }
|
|
||||||
| Gt { left, right }
|
|
||||||
| Eq { left, right }
|
|
||||||
| Neq { left, right }
|
|
||||||
| And { left, right }
|
|
||||||
| Or { left, right } => {
|
|
||||||
let left = self.eval_expr(left)?;
|
|
||||||
let right = self.eval_expr(right)?;
|
|
||||||
|
|
||||||
match expr {
|
|
||||||
// Arithmetic operators.
|
// Arithmetic operators.
|
||||||
Add { .. }
|
Add | Subtract | Multiply | Divide => {
|
||||||
| Subtract { .. }
|
let lhs = i32::try_from(lhs)?;
|
||||||
| Multiply { .. }
|
let rhs = i32::try_from(rhs)?;
|
||||||
| Divide { .. } => {
|
|
||||||
let left = i32::try_from(left)?;
|
|
||||||
let right = i32::try_from(right)?;
|
|
||||||
|
|
||||||
let res = match expr {
|
let res = match kind {
|
||||||
Add { .. } => left.checked_add(right),
|
Add => lhs.checked_add(rhs),
|
||||||
Subtract { .. } => left.checked_sub(right),
|
Subtract => lhs.checked_sub(rhs),
|
||||||
Multiply { .. } => left.checked_mul(right),
|
Multiply => lhs.checked_mul(rhs),
|
||||||
Divide { .. } => left.checked_div(right),
|
Divide => lhs.checked_div(rhs),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
.ok_or(Error {
|
.ok_or(Error {
|
||||||
kind: ErrorKind::ArithmeticError,
|
kind: ErrorKind::ArithmeticError,
|
||||||
span: 0..0,
|
span: expr.span.clone(),
|
||||||
})?;
|
})?;
|
||||||
Int(res)
|
Int(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Numeric comparisons.
|
// Numeric comparisons.
|
||||||
Lt { .. } | Gt { .. } => {
|
Less | Greater => {
|
||||||
let left = i32::try_from(left)?;
|
let lhs = i32::try_from(lhs)?;
|
||||||
let right = i32::try_from(right)?;
|
let rhs = i32::try_from(rhs)?;
|
||||||
|
|
||||||
let res = match expr {
|
let res = match kind {
|
||||||
Lt { .. } => left < right,
|
Less => lhs < rhs,
|
||||||
Gt { .. } => left > right,
|
Greater => lhs > rhs,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
Bool(res)
|
Bool(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// General comparisons.
|
// General comparisons.
|
||||||
Eq { .. } | Neq { .. } => {
|
Equal | NotEqual => {
|
||||||
let res = match expr {
|
let res = match kind {
|
||||||
Eq { .. } => left == right,
|
Equal => lhs == rhs,
|
||||||
Neq { .. } => left != right,
|
NotEqual => lhs != rhs,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
Bool(res)
|
Bool(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logical connectives.
|
// Logical connectives.
|
||||||
And { .. } | Or { .. } => {
|
And | Or => {
|
||||||
let left = bool::from(left);
|
let lhs = bool::from(lhs);
|
||||||
let right = bool::from(right);
|
let rhs = bool::from(rhs);
|
||||||
let res = match expr {
|
let res = match kind {
|
||||||
And { .. } => left && right,
|
And => lhs && rhs,
|
||||||
Or { .. } => left || right,
|
Or => lhs || rhs,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
Bool(res)
|
Bool(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// That's all the binary operations.
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Not(expr) => Bool(!bool::from(self.eval_expr(expr)?)),
|
Not(expr) => Bool(!bool::from(self.eval_expr(&expr)?)),
|
||||||
Literal(value) => value.clone(),
|
Literal(value) => value.clone(),
|
||||||
Identifier(Iden(name)) => self.get_var(name)?,
|
Variable(name) => self.get_var(&name)?,
|
||||||
|
// Binary expressions.
|
||||||
|
// Add | Subtract | Multiply | Divide | Lt | Gt | Eq | Neq | And | Or => {
|
||||||
|
// let lhs = self.eval_expr(lhs)?;
|
||||||
|
// let rhs = self.eval_expr(rhs)?;
|
||||||
|
|
||||||
|
// match expr {
|
||||||
|
// // Arithmetic operators.
|
||||||
|
// Add { .. } | Subtract { .. } | Multiply { .. } | Divide { .. } => {
|
||||||
|
// let lhs = i32::try_from(lhs)?;
|
||||||
|
// let rhs = i32::try_from(rhs)?;
|
||||||
|
|
||||||
|
// let res = match expr {
|
||||||
|
// Add { .. } => lhs.checked_add(rhs),
|
||||||
|
// Subtract { .. } => lhs.checked_sub(rhs),
|
||||||
|
// Multiply { .. } => lhs.checked_mul(rhs),
|
||||||
|
// Divide { .. } => lhs.checked_div(rhs),
|
||||||
|
// _ => unreachable!(),
|
||||||
|
// }
|
||||||
|
// .ok_or(Error {
|
||||||
|
// kind: ErrorKind::ArithmeticError,
|
||||||
|
// position: 0..0,
|
||||||
|
// })?;
|
||||||
|
// Int(res)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Numeric comparisons.
|
||||||
|
// Lt { .. } | Gt { .. } => {
|
||||||
|
// let lhs = i32::try_from(lhs)?;
|
||||||
|
// let rhs = i32::try_from(rhs)?;
|
||||||
|
|
||||||
|
// let res = match expr {
|
||||||
|
// Lt { .. } => lhs < rhs,
|
||||||
|
// Gt { .. } => lhs > rhs,
|
||||||
|
// _ => unreachable!(),
|
||||||
|
// };
|
||||||
|
// Bool(res)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // General comparisons.
|
||||||
|
// Eq { .. } | Neq { .. } => {
|
||||||
|
// let res = match expr {
|
||||||
|
// Eq { .. } => lhs == rhs,
|
||||||
|
// Neq { .. } => lhs != rhs,
|
||||||
|
// _ => unreachable!(),
|
||||||
|
// };
|
||||||
|
// Bool(res)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Logical connectives.
|
||||||
|
// And { .. } | Or { .. } => {
|
||||||
|
// let lhs = bool::from(lhs);
|
||||||
|
// let rhs = bool::from(rhs);
|
||||||
|
// let res = match expr {
|
||||||
|
// And { .. } => lhs && rhs,
|
||||||
|
// Or { .. } => lhs || rhs,
|
||||||
|
// _ => unreachable!(),
|
||||||
|
// };
|
||||||
|
// Bool(res)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // That's all the binary operations.
|
||||||
|
// _ => unreachable!(),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// Not(expr) => Bool(!bool::from(self.eval_expr(expr)?)),
|
||||||
|
// Literal(value) => value.clone(),
|
||||||
|
// Identifier(Iden(name)) => self.get_var(name)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Perform the action indicated by a statement.
|
/// Perform the action indicated by a statement.
|
||||||
fn eval_stmt(&mut self, stmt: &Stmt) -> Result<HaltStatus, Error> {
|
fn eval_stmt(&mut self, stmt: &Stmt) -> Result<HaltStatus, Error> {
|
||||||
match stmt {
|
match &stmt.kind {
|
||||||
Stmt::Print(expr) => {
|
StmtKind::Print(expr) => {
|
||||||
println!("{}", self.eval_expr(expr)?);
|
println!("{}", self.eval_expr(expr)?);
|
||||||
}
|
}
|
||||||
Stmt::VariableDeclaration { iden, init } => {
|
StmtKind::Var { iden, init } => {
|
||||||
let init = match init {
|
let init = match init {
|
||||||
Some(e) => self.eval_expr(e)?,
|
Some(e) => self.eval_expr(e)?,
|
||||||
None => Value::Nul,
|
None => Value::Nul,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.decl_var(&iden.0, init);
|
self.decl_var(&iden.iden, init);
|
||||||
}
|
}
|
||||||
Stmt::FunctionDeclaration {
|
StmtKind::Functio {
|
||||||
iden: _,
|
iden: _,
|
||||||
args: _,
|
args: _,
|
||||||
body: _,
|
body: _,
|
||||||
} => todo!(),
|
} => todo!(),
|
||||||
Stmt::BfFDeclaration { iden, body } => {
|
// This is missing from StmtKind after the interpreter
|
||||||
self.decl_var(
|
// rewrite; presumably, parsing is not yet implemented for
|
||||||
&iden.0,
|
// it. ~~Alex
|
||||||
Value::Functio(Functio::BfFunctio(body.as_bytes().into())),
|
// StmtKind::BfFDeclaration { iden, body } => {
|
||||||
);
|
// self.decl_var(
|
||||||
}
|
// &iden.0,
|
||||||
Stmt::If { cond, body } => {
|
// Value::Functio(Functio::BfFunctio(body.as_bytes().into())),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
StmtKind::If { cond, body } => {
|
||||||
if self.eval_expr(cond)?.into() {
|
if self.eval_expr(cond)?.into() {
|
||||||
return self.eval_items_hs(body);
|
return self.eval_stmts_hs(&body.block);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Stmt::FunctionCall { iden, args } => {
|
StmtKind::Call { iden, args } => {
|
||||||
let func = self.get_var(&iden.0)?;
|
let func = self.get_var(&iden.iden)?;
|
||||||
match func {
|
match func {
|
||||||
Value::Functio(func) => {
|
Value::Functio(func) => {
|
||||||
match func {
|
match func {
|
||||||
|
@ -246,7 +290,7 @@ impl ExecEnv {
|
||||||
crate::brian::interpret_with_io(&body, &input as &[_], &mut output)
|
crate::brian::interpret_with_io(&body, &input as &[_], &mut output)
|
||||||
.map_err(|e| Error {
|
.map_err(|e| Error {
|
||||||
kind: ErrorKind::BfInterpretError(e),
|
kind: ErrorKind::BfInterpretError(e),
|
||||||
span: 0..0,
|
span: stmt.span.clone(),
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
// I guess Brainfuck functions write
|
// I guess Brainfuck functions write
|
||||||
|
@ -263,31 +307,37 @@ impl ExecEnv {
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Error {
|
return Err(Error {
|
||||||
kind: ErrorKind::TypeError(iden.0.to_owned()),
|
kind: ErrorKind::TypeError(iden.iden.to_owned()),
|
||||||
span: 0..0,
|
span: stmt.span.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Stmt::Loop { body } => loop {
|
StmtKind::Loop { body } => loop {
|
||||||
let res = self.eval_items_hs(body)?;
|
let res = self.eval_stmts_hs(&body.block)?;
|
||||||
match res {
|
match res {
|
||||||
HaltStatus::Value(_) => {}
|
HaltStatus::Value(_) => {}
|
||||||
HaltStatus::Break => break,
|
HaltStatus::Break => break,
|
||||||
HaltStatus::Hopback => continue,
|
HaltStatus::Hopback => continue,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Stmt::VarAssignment { iden, value } => {
|
// This is missing as well. ~~Alex
|
||||||
self.get_var_mut(&iden.0)?.value = self.eval_expr(value)?;
|
// StmtKind::VarAssignment { iden, value } => {
|
||||||
}
|
// self.get_var_mut(&iden.0)?.value = self.eval_expr(value)?;
|
||||||
Stmt::Break => {
|
// }
|
||||||
|
StmtKind::Break => {
|
||||||
return Ok(HaltStatus::Break);
|
return Ok(HaltStatus::Break);
|
||||||
}
|
}
|
||||||
Stmt::HopBack => {
|
StmtKind::HopBack => {
|
||||||
return Ok(HaltStatus::Hopback);
|
return Ok(HaltStatus::Hopback);
|
||||||
}
|
}
|
||||||
Stmt::Melo(iden) => {
|
StmtKind::Melo(iden) => {
|
||||||
self.get_var_mut(&iden.0)?.melo = true;
|
self.get_var_mut(&iden.iden)?.melo = true;
|
||||||
|
}
|
||||||
|
StmtKind::Rlyeh => {
|
||||||
|
// Maybe print a creepy error message or something
|
||||||
|
// here at some point. ~~Alex
|
||||||
|
exit(random());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -371,6 +421,8 @@ impl ExecEnv {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use crate::ast::ExprKind;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -378,10 +430,20 @@ mod tests {
|
||||||
// Check that 2 + 2 = 4.
|
// Check that 2 + 2 = 4.
|
||||||
let mut env = ExecEnv::new();
|
let mut env = ExecEnv::new();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
env.eval_items(&[Item::Expr(Expr::Add {
|
env.eval_expr(&Expr {
|
||||||
left: Box::new(Expr::Literal(Value::Int(2))),
|
kind: ExprKind::BinOp {
|
||||||
right: Box::new(Expr::Literal(Value::Int(2))),
|
lhs: Box::new(Expr {
|
||||||
})])
|
kind: ExprKind::Literal(Value::Int(2)),
|
||||||
|
span: 0..0,
|
||||||
|
}),
|
||||||
|
rhs: Box::new(Expr {
|
||||||
|
kind: ExprKind::Literal(Value::Int(2)),
|
||||||
|
span: 0..0,
|
||||||
|
}),
|
||||||
|
kind: crate::ast::BinOpKind::Add,
|
||||||
|
},
|
||||||
|
span: 0..0
|
||||||
|
})
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
Value::Int(4)
|
Value::Int(4)
|
||||||
)
|
)
|
||||||
|
@ -393,10 +455,20 @@ mod tests {
|
||||||
// error.
|
// error.
|
||||||
let mut env = ExecEnv::new();
|
let mut env = ExecEnv::new();
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
env.eval_items(&[Item::Expr(Expr::Add {
|
env.eval_expr(&Expr {
|
||||||
left: Box::new(Expr::Literal(Value::Int(i32::MAX))),
|
kind: ExprKind::BinOp {
|
||||||
right: Box::new(Expr::Literal(Value::Bool(false))),
|
lhs: Box::new(Expr {
|
||||||
})]),
|
kind: ExprKind::Literal(Value::Int(2)),
|
||||||
|
span: 0..0,
|
||||||
|
}),
|
||||||
|
rhs: Box::new(Expr {
|
||||||
|
kind: ExprKind::Literal(Value::Bool(true)),
|
||||||
|
span: 0..0,
|
||||||
|
}),
|
||||||
|
kind: crate::ast::BinOpKind::Add,
|
||||||
|
},
|
||||||
|
span: 0..0
|
||||||
|
}),
|
||||||
Err(Error {
|
Err(Error {
|
||||||
kind: ErrorKind::TypeError(_),
|
kind: ErrorKind::TypeError(_),
|
||||||
span: _,
|
span: _,
|
||||||
|
@ -410,10 +482,20 @@ mod tests {
|
||||||
// of panicking.
|
// of panicking.
|
||||||
let mut env = ExecEnv::new();
|
let mut env = ExecEnv::new();
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
env.eval_items(&[Item::Expr(Expr::Add {
|
env.eval_expr(&Expr {
|
||||||
left: Box::new(Expr::Literal(Value::Int(i32::MAX))),
|
kind: ExprKind::BinOp {
|
||||||
right: Box::new(Expr::Literal(Value::Int(1))),
|
lhs: Box::new(Expr {
|
||||||
})]),
|
kind: ExprKind::Literal(Value::Int(i32::MAX)),
|
||||||
|
span: 0..0,
|
||||||
|
}),
|
||||||
|
rhs: Box::new(Expr {
|
||||||
|
kind: ExprKind::Literal(Value::Int(1)),
|
||||||
|
span: 0..0,
|
||||||
|
}),
|
||||||
|
kind: crate::ast::BinOpKind::Add,
|
||||||
|
},
|
||||||
|
span: 0..0
|
||||||
|
}),
|
||||||
Err(Error {
|
Err(Error {
|
||||||
kind: ErrorKind::ArithmeticError,
|
kind: ErrorKind::ArithmeticError,
|
||||||
span: _,
|
span: _,
|
||||||
|
@ -422,10 +504,20 @@ mod tests {
|
||||||
|
|
||||||
// And the same for divide by zero.
|
// And the same for divide by zero.
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
env.eval_items(&[Item::Expr(Expr::Divide {
|
env.eval_expr(&Expr {
|
||||||
left: Box::new(Expr::Literal(Value::Int(1))),
|
kind: ExprKind::BinOp {
|
||||||
right: Box::new(Expr::Literal(Value::Int(0))),
|
lhs: Box::new(Expr {
|
||||||
})]),
|
kind: ExprKind::Literal(Value::Int(1)),
|
||||||
|
span: 0..0,
|
||||||
|
}),
|
||||||
|
rhs: Box::new(Expr {
|
||||||
|
kind: ExprKind::Literal(Value::Int(0)),
|
||||||
|
span: 0..0,
|
||||||
|
}),
|
||||||
|
kind: crate::ast::BinOpKind::Add,
|
||||||
|
},
|
||||||
|
span: 0..0
|
||||||
|
}),
|
||||||
Err(Error {
|
Err(Error {
|
||||||
kind: ErrorKind::ArithmeticError,
|
kind: ErrorKind::ArithmeticError,
|
||||||
span: _,
|
span: _,
|
||||||
|
|
|
@ -43,7 +43,7 @@ fn main() {
|
||||||
Ok(ast) => {
|
Ok(ast) => {
|
||||||
println!("{:#?}", ast);
|
println!("{:#?}", ast);
|
||||||
let mut env = ExecEnv::new();
|
let mut env = ExecEnv::new();
|
||||||
println!("{:?}", env.eval_items(&ast));
|
println!("{:?}", env.eval_stmts(&ast));
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!(
|
println!(
|
||||||
|
|
|
@ -19,7 +19,7 @@ pub fn repl() {
|
||||||
match ast {
|
match ast {
|
||||||
Ok(ast) => {
|
Ok(ast) => {
|
||||||
println!("{:?}", ast);
|
println!("{:?}", ast);
|
||||||
println!("{:?}", env.eval_items(&ast));
|
println!("{:?}", env.eval_stmts(&ast));
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!(
|
println!(
|
||||||
|
|
|
@ -2,8 +2,11 @@ use std::{convert::TryFrom, fmt::Display, io::Write};
|
||||||
|
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
||||||
use crate::ast::{Expr, Stmt};
|
use crate::{
|
||||||
use crate::error::{Error, ErrorKind};
|
ast::Stmt,
|
||||||
|
error::{Error, ErrorKind},
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum Abool {
|
pub enum Abool {
|
||||||
Never = -1,
|
Never = -1,
|
||||||
|
@ -31,13 +34,13 @@ impl From<Abool> for bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum Functio {
|
pub enum Functio {
|
||||||
BfFunctio(Vec<u8>),
|
BfFunctio(Vec<u8>),
|
||||||
AbleFunctio(Vec<Stmt>),
|
AbleFunctio(Vec<Stmt>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum Value {
|
pub enum Value {
|
||||||
Nul,
|
Nul,
|
||||||
Str(String),
|
Str(String),
|
||||||
|
|
Loading…
Reference in a new issue