13 unstable releases (3 breaking)

Uses old Rust 2015

0.7.1 May 25, 2016
0.6.0 May 24, 2016
0.1.5 Dec 27, 2015
0.1.4 Jun 24, 2015
0.0.2 Mar 2, 2015

#15 in #false

46 downloads per month

MIT and GPL licenses

18KB
331 lines

repl

Generic REPL trait

Version

Crates.io Build Status


lib.rs:

R(ead), E(val), P(rint), L(oop)

use repl::{Repl, ReplEnv};
use self::CmdType::*;
use self::Exp::*;
use self::ReplErr::{Read, Eval};
use std::default::Default;
use std::fmt;

pub struct MyRepl;

#[derive(Default)]
pub struct MyReplEnv {
    prompt: String,
}

impl ReplEnv for MyReplEnv {
    fn preamble(&self) -> bool {
        false
    }

    fn colorize(&self) -> bool {
        false
    }

    fn prompt(&self) -> &str {
        &self.prompt
    }
}

pub enum CmdType {
    Open,
    Close,
}

pub enum Exp {
    Cmd(CmdType),
    Strn(String),
    Exit,
    Nil,
}

pub enum ReplErr {
    Read(&'static str),
    Eval(&'static str), // Print(String),
}

impl fmt::Display for ReplErr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let x = match *self {
            Read(ref x) => x,
            Eval(ref x) => x,
            // Print(ref x) => x,
        };
        write!(f, "{}", x)
    }
}

pub type MyReplResult = Result<Exp, ReplErr>;

impl Repl<Exp, ReplErr, MyReplEnv> for MyRepl {
    fn preamble(&self, _: &MyReplEnv) -> &MyRepl {
        self
    }

    fn read(&self, input: String, _: &MyReplEnv) -> MyReplResult {
        match &input[..] {
            "open" | "close" | "exit" => Ok(Strn(input)),
            _ => Err(Read("invalid input")),
        }
    }

    fn eval(&self, cmd: Exp, _: &MyReplEnv) -> MyReplResult {
        match cmd {
            Strn(ref x) if *x == "open" => Ok(Cmd(Open)),
            Strn(ref x) if *x == "close" => Ok(Cmd(Close)),
            Strn(ref x) if *x == "exit" => Ok(Exit),
            _ => Err(Eval("invalid ast")),
        }
    }

    fn print(&self, cmd: Exp, _: &MyReplEnv) -> MyReplResult {
        match cmd {
            Cmd(Open) => {
                println!("opening...");
                Ok(Nil)
            }
            Cmd(Close) => {
                println!("closing...");
                Ok(Nil)
            }
            Exit => {
                println!("exiting...");
                Ok(Exit)
            }
            _ => Ok(Nil),
        }
    }

    fn break_loop(&self, cmd: &Exp, _: &MyReplEnv) -> bool {
        match *cmd {
            Exit => true,
            _ => false,
        }
    }
}

fn main() {
    let repl = MyRepl;
    let env: MyReplEnv = Default::default();
    test_read(&repl, &env);
    test_eval(&repl, &env);
    test_print(&repl, &env);
    test_read_eval_print(&repl, &env);
    test_break_loop(&repl, &env);
}

fn test_read(repl: &MyRepl, env: &MyReplEnv) {
    assert!(repl.read("open".to_owned(), env).is_ok());
    assert!(repl.read("close".to_owned(), env).is_ok());
    assert!(repl.read("exit".to_owned(), env).is_ok());
    assert!(repl.read("blah".to_owned(), env).is_err());
}

fn test_eval(repl: &MyRepl, env: &MyReplEnv) {
    assert!(repl.eval(Strn("open".to_owned()), &env).is_ok());
    assert!(repl.eval(Strn("close".to_owned()), &env).is_ok());
    assert!(repl.eval(Strn("exit".to_owned()), &env).is_ok());
    assert!(repl.eval(Nil, &env).is_err());
}

fn test_print(repl: &MyRepl, env: &MyReplEnv) {
    assert!(repl.print(Cmd(Open), &env).is_ok());
    assert!(repl.print(Cmd(Close), &env).is_ok());
    assert!(repl.print(Exit, &env).is_ok());
    assert!(repl.print(Nil, &env).is_ok());
}

fn test_read_eval_print(repl: &MyRepl, env: &MyReplEnv) {
    assert!(repl.read("open".to_owned(), &env)
                .and_then(|r| repl.eval(r, &env))
                .and_then(|r| repl.print(r, &env))
                .is_ok());
    assert!(repl.read("close".to_owned(), &env)
                .and_then(|r| repl.eval(r, &env))
                .and_then(|r| repl.print(r, &env))
                .is_ok());
    assert!(repl.read("blah".to_owned(), &env)
                .and_then(|r| repl.eval(r, &env))
                .and_then(|r| repl.print(r, &env))
                .is_err());
}

fn test_break_loop(repl: &MyRepl, env: &MyReplEnv) {
    assert!(repl.break_loop(&Exit, &env));
    assert!(!repl.break_loop(&Cmd(Open), &env));
}

Dependencies

~3.5MB
~52K SLoC