mimium_lang/
repl.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
use crate::{
    ast_interpreter::{self, PValue, Value},
    compiler::{self, interpret_top},
    interner::ToSymbol,
    utils::{error, miniprint::MiniPrint},
};
use std::io::{stdin, stdout, Write};

pub enum ReplMode {
    Eval,
    EvalMulti(u64),
    ShowAST,
}
pub struct ReplAppData {
    line_count: u64,
    global_ctx: ast_interpreter::Context,
    mode: ReplMode,
}
impl Default for ReplAppData {
    fn default() -> Self {
        Self {
            line_count: 0,
            global_ctx: ast_interpreter::Context::default(),
            mode: ReplMode::Eval,
        }
    }
}

fn process_command(mode_str: &str) -> Option<ReplMode> {
    match mode_str {
        ":e" => {
            println!("Mode:Eval");
            Some(ReplMode::Eval)
        }
        ":m" => {
            println!("Mode:EvalMulti");
            Some(ReplMode::EvalMulti(3))
        }
        ":a" => {
            println!("Mode:AST");
            Some(ReplMode::ShowAST)
        }

        _ => None,
    }
}

fn repl(data: &mut ReplAppData) -> ! {
    let mut src = String::new();
    loop {
        print!("> ");
        let _ = stdout().flush();
        let mut src_tmp = String::new();
        let _size = stdin().read_line(&mut src_tmp).expect("stdin read error.");
        src = format!("{}{}", src, src_tmp);
        if let Some(mode) = process_command(&src[0..2]) {
            data.mode = mode;
            src.clear();
        } else {
            let _ = src.pop(); //remove last linebreak
            if !src.as_str().ends_with('\\') {
                match data.mode {
                    ReplMode::Eval => match interpret_top(src.clone(), &mut data.global_ctx) {
                        Ok(v) => {
                            println!("{:?}", v);
                        }
                        Err(e) => error::report(&src, "".to_symbol(), &e),
                    },
                    ReplMode::EvalMulti(n) => {
                        let mut res = Ok(Value::Primitive(PValue::Numeric(0.0)));
                        for _i in 0..n {
                            res = interpret_top(src.clone(), &mut data.global_ctx);
                            data.global_ctx.history.0 = 0;
                        }
                        match res {
                            Ok(v) => {
                                println!("{:?}", v);
                            }
                            Err(e) => error::report(&src, "".to_symbol(), &e),
                        }
                    }
                    ReplMode::ShowAST => match compiler::emit_ast(&src, None) {
                        Ok(ast) => {
                            println!("{}", ast.pretty_print());
                        }
                        Err(e) => error::report(&src, "".to_symbol(), &e),
                    },
                }
                src.clear();
            } else {
                src.pop(); //remove last backslash
            }

            data.line_count += 1;
        }
    }
}

pub fn run_repl() {
    repl(&mut ReplAppData::default())
}