Permalink
Browse files

feat(evaluator): Implement basic evaluator

  • Loading branch information...
mizdra committed Jan 5, 2019
1 parent 637cca2 commit e9c8aa006b1fed4f95a2c1e4795143aaf586ea59
Showing with 279 additions and 6 deletions.
  1. +18 −0 src/error.rs
  2. +213 −0 src/evaluator/mod.rs
  3. +31 −0 src/evaluator/object.rs
  4. +6 −2 src/lib.rs
  5. +4 −0 src/parser/ast.rs
  6. +7 −4 src/repl/main.rs
@@ -0,0 +1,18 @@
use std::{error, fmt};

#[derive(Debug, Clone, PartialEq)]
pub enum Error {
RuntimeError(String),
}

impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Error::RuntimeError(msg) => write!(f, "runtime error: {}", msg),
}
}
}

impl error::Error for Error {}

pub type Result<T> = std::result::Result<T, Error>;
@@ -0,0 +1,213 @@
mod object;

use crate::error::*;

pub use self::object::Object;

use crate::ast::*;

fn error(msg: String) -> Result<Object> {
Err(Error::RuntimeError(msg))
}

pub struct Evaluator {}

impl Evaluator {
pub fn new() -> Evaluator {
Evaluator {}
}

fn eval_literal(&mut self, literal: Literal) -> Result<Object> {
match literal {
Literal::Int(val) => Ok(Object::Int(val)),
Literal::String(val) => Ok(Object::String(val)),
Literal::Bool(val) => Ok(Object::Bool(val)),
}
}

fn eval_prefix(&mut self, prefix: Prefix, expr: Expr) -> Result<Object> {
let object = self.eval_expr(expr)?;
match prefix {
Prefix::Plus => Ok(object),
Prefix::Minus => {
if let Object::Int(val) = object {
Ok(Object::Int(-val))
} else {
error(format!(
"no operator `-` found for `{}`",
object.get_type_name()
))
}
}
Prefix::Not => {
if let Object::Bool(val) = object {
Ok(Object::Bool(!val))
} else {
error(format!(
"no operator `!` found for `{}`",
object.get_type_name()
))
}
}
}
}

fn eval_infix(&mut self, infix: Infix, left: Expr, right: Expr) -> Result<Object> {
let left = self.eval_expr(left)?;
let right = self.eval_expr(right)?;
match (infix, left, right) {
(Infix::Plus, Object::Int(l_val), Object::Int(r_val)) => Ok(Object::Int(l_val + r_val)),
(Infix::Minus, Object::Int(l_val), Object::Int(r_val)) => {
Ok(Object::Int(l_val - r_val))
}
(Infix::Divide, Object::Int(l_val), Object::Int(r_val)) => {
Ok(Object::Int(l_val / r_val))
}
(Infix::Multiply, Object::Int(l_val), Object::Int(r_val)) => {
Ok(Object::Int(l_val * r_val))
}
(Infix::Equal, left, right) => match (left, right) {
(Object::Int(l_val), Object::Int(r_val)) => Ok(Object::Bool(l_val == r_val)),
(Object::String(l_val), Object::String(r_val)) => Ok(Object::Bool(l_val == r_val)),
(Object::Bool(l_val), Object::Bool(r_val)) => Ok(Object::Bool(l_val == r_val)),
(Object::Unit, Object::Unit) => Ok(Object::Bool(true)),
(left, right) => error(format!(
"no implementation for `{} == {}`",
left.get_type_name(),
right.get_type_name(),
)),
},
(Infix::NotEqual, left, right) => match (left, right) {
(Object::Int(l_val), Object::Int(r_val)) => Ok(Object::Bool(l_val != r_val)),
(Object::String(l_val), Object::String(r_val)) => Ok(Object::Bool(l_val != r_val)),
(Object::Bool(l_val), Object::Bool(r_val)) => Ok(Object::Bool(l_val != r_val)),
(Object::Unit, Object::Unit) => Ok(Object::Bool(false)),
(left, right) => error(format!(
"no implementation for `{} != {}`",
left.get_type_name(),
right.get_type_name(),
)),
},
(Infix::GreaterThanEqual, Object::Int(l_val), Object::Int(r_val)) => {
Ok(Object::Bool(l_val >= r_val))
}
(Infix::GreaterThan, Object::Int(l_val), Object::Int(r_val)) => {
Ok(Object::Bool(l_val > r_val))
}
(Infix::LessThanEqual, Object::Int(l_val), Object::Int(r_val)) => {
Ok(Object::Bool(l_val <= r_val))
}
(Infix::LessThan, Object::Int(l_val), Object::Int(r_val)) => {
Ok(Object::Bool(l_val < r_val))
}
(infix, left, right) => error(format!(
"no implementation for `{} {} {}`",
left.get_type_name(),
infix,
right.get_type_name(),
)),
}
}

fn eval_expr(&mut self, expr: Expr) -> Result<Object> {
match expr {
Expr::Literal(literal) => self.eval_literal(literal),
Expr::Prefix(prefix, e) => self.eval_prefix(prefix, *e),
Expr::Infix(infix, left, right) => self.eval_infix(infix, *left, *right),
_ => unimplemented!(),
}
}

fn eval_stmt(&mut self, stmt: Stmt) -> Result<Object> {
match stmt {
// Stmt::Let(ident, expr) => self.eval_let_stmt(ident, expr),
// Stmt::Return => self.eval_return_stmt(stmt),
Stmt::Expr(expr) => self.eval_expr(expr),
_ => unimplemented!(),
}
}

fn eval_block_stmt(&mut self, block_stmt: BlockStmt) -> Result<Object> {
let mut result = Ok(Object::Unit);
for stmt in block_stmt {
result = self.eval_stmt(stmt);
}
result
}

pub fn eval(&mut self, program: Program) -> Result<Object> {
self.eval_block_stmt(program)
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::{Lexer, Parser};

fn eval(src: &str) -> Object {
let mut parser = Parser::new(Lexer::new(src));
let program = parser.parse();
let mut evaluator = Evaluator::new();
match evaluator.eval(program) {
Ok(object) => object,
Err(err) => panic!(err),
}
}

#[test]
fn test_expr_stmt() {
// 優先順位のテストは parser の責務であるため, ここではテストしない

// リテラル
assert_eq!(eval("0"), Object::Int(0));
assert_eq!(eval("\"str\""), Object::String("str".to_string()));
assert_eq!(eval("true"), Object::Bool(true));

// 基本的な演算
assert_eq!(eval("1 + 2"), Object::Int(1 + 2));
assert_eq!(eval("1 + -2"), Object::Int(1 + -2));
assert_eq!(eval("1 - 2"), Object::Int(1 - 2));
assert_eq!(eval("1 - -2"), Object::Int(1 - -2));
assert_eq!(eval("2 * 3"), Object::Int(2 * 3));
assert_eq!(eval("2 * -3"), Object::Int(2 * -3));
assert_eq!(eval("-2 * -3"), Object::Int(-2 * -3));
assert_eq!(eval("2 / 3"), Object::Int(2 / 3));
assert_eq!(eval("2 / -3"), Object::Int(2 / -3));
assert_eq!(eval("-2 / -3"), Object::Int(-2 / -3));
assert_eq!(eval("1 == 1"), Object::Bool(1 == 1));
assert_eq!(eval("1 == 2"), Object::Bool(1 == 2));
assert_eq!(eval("true == true"), Object::Bool(true == true));
assert_eq!(eval("true == false"), Object::Bool(true == false));
assert_eq!(eval("\"str\" == \"str\""), Object::Bool("str" == "str"));
assert_eq!(eval("\"str\" == \"\""), Object::Bool("str" == ""));
assert_eq!(eval("1 != 1"), Object::Bool(1 != 1));
assert_eq!(eval("1 != 2"), Object::Bool(1 != 2));
assert_eq!(eval("true != true"), Object::Bool(true != true));
assert_eq!(eval("true != false"), Object::Bool(true != false));
assert_eq!(eval("\"str\" != \"str\""), Object::Bool("str" != "str"));
assert_eq!(eval("\"str\" != \"\""), Object::Bool("str" != ""));
assert_eq!(eval("1 >= 0"), Object::Bool(1 >= 0));
assert_eq!(eval("1 >= 1"), Object::Bool(1 >= 1));
assert_eq!(eval("1 >= 2"), Object::Bool(1 >= 2));
assert_eq!(eval("1 > 0"), Object::Bool(1 > 0));
assert_eq!(eval("1 > 1"), Object::Bool(1 > 1));
assert_eq!(eval("1 > 2"), Object::Bool(1 > 2));
assert_eq!(eval("0 <= 1"), Object::Bool(0 <= 1));
assert_eq!(eval("1 <= 1"), Object::Bool(1 <= 1));
assert_eq!(eval("2 <= 1"), Object::Bool(2 <= 1));
assert_eq!(eval("0 < 1"), Object::Bool(0 < 1));
assert_eq!(eval("1 < 1"), Object::Bool(1 < 1));
assert_eq!(eval("2 < 1"), Object::Bool(2 < 1));

// 複雑な演算
assert_eq!(
eval("1 + 2 * 3 + 4 * (5 - 6)"),
Object::Int(1 + 2 * 3 + 4 * (5 - 6))
);
assert_eq!(
eval("!!(!(!!!(0 == 0)) == (1 == 2))"),
Object::Bool(!!(!(!!!(0 == 0)) == (1 == 2)))
);
}
}
@@ -0,0 +1,31 @@
use std::fmt;

#[derive(Debug, Clone, PartialEq)]
pub enum Object {
Int(i64),
String(String),
Bool(bool),
Unit,
}

impl Object {
pub fn get_type_name(&self) -> &str {
match self {
Object::Int(_) => "Int",
Object::String(_) => "String",
Object::Bool(_) => "Bool",
Object::Unit => "Unit",
}
}
}

impl fmt::Display for Object {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Object::Int(val) => write!(f, "{}", val),
Object::String(val) => write!(f, "\"{}\"", val),
Object::Bool(val) => write!(f, "{}", val),
Object::Unit => write!(f, "()"),
}
}
}
@@ -1,5 +1,9 @@
mod error;
mod evaluator;
mod lexer;
mod parser;

pub use self::lexer::{Lexer, Token};
pub use self::parser::{ast, Parser};
pub use self::error::*;
pub use self::evaluator::*;
pub use self::lexer::*;
pub use self::parser::*;
@@ -1,5 +1,9 @@
use std::fmt;

trait Operator {}
impl Operator for Prefix {}
impl Operator for Infix {}

#[derive(PartialEq, Clone, Debug)]
pub struct Ident(pub String);

@@ -1,9 +1,10 @@
use rustyline::error::ReadlineError;
use rustyline::Editor;
use shiki::{Lexer, Parser};
use shiki::{Evaluator, Lexer, Parser};

fn main() {
let mut rl = Editor::<()>::new();
let mut evaluator = Evaluator::new();

loop {
let readline = rl.readline("\x1b[34m>> \x1b[0m");
@@ -14,9 +15,11 @@ fn main() {

let mut parser = Parser::new(Lexer::new(code));
let program = parser.parse();
for stmt in program {
println!("{}", stmt);
}

match evaluator.eval(program) {
Ok(object) => println!("{}", object),
Err(error) => eprintln!("\x1b[31m{}\x1b[0m", error),
};
}
Err(ReadlineError::Interrupted) | Err(ReadlineError::Eof) => {
println!("bye");

0 comments on commit e9c8aa0

Please sign in to comment.