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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
mod arret_helper;
mod command;
mod history;
mod syntax;
use std::io::prelude::*;
use std::io::BufReader;
use std::sync::Arc;
use std::{fs, path};
use ansi_term::{Colour, Style};
use arret_compiler::{emit_diagnostics_to_stderr, CompileCtx};
use arret_helper::ArretHelper;
use command::{parse_command, ParsedCommand};
use history::repl_history_path;
const PROMPT: &str = "arret> ";
pub fn interactive_loop(ccx: Arc<CompileCtx>, include_path: Option<path::PathBuf>) {
use arret_compiler::repl::{EvalKind, EvaledExprValue, EvaledLine};
use rustyline::error::ReadlineError;
let repl_ctx = arret_compiler::repl::ReplCtx::new(ccx.clone());
let mut rl = rustyline::Editor::<ArretHelper>::new();
let initial_import = "(import [stdlib base])".to_owned();
repl_ctx.send_line(initial_import, EvalKind::Value).unwrap();
let mut sent_prelude_lines = 1;
if let Some(include_path) = include_path {
let include_file = fs::File::open(include_path).unwrap();
for line in BufReader::new(include_file).lines() {
repl_ctx.send_line(line.unwrap(), EvalKind::Value).unwrap();
sent_prelude_lines += 1
}
}
let history_path = repl_history_path();
if let Some(ref history_path) = history_path {
let _ = rl.load_history(history_path);
}
for _ in 0..sent_prelude_lines {
match repl_ctx.receive_result() {
Ok(EvaledLine::Defs(bound_names)) => {
rl.set_helper(Some(ArretHelper::new(bound_names)));
}
Ok(_) => {}
Err(diagnostics) => emit_diagnostics_to_stderr(ccx.source_loader(), diagnostics),
}
}
let defs_style = Colour::Purple.bold();
let expr_arrow_style = Colour::Green.bold();
let type_style = Colour::Fixed(166);
let type_brackets_style = Style::new().dimmed();
loop {
let mut history_dirty = false;
let readline = rl.readline(PROMPT);
match readline {
Ok(line) => {
if !line.chars().all(char::is_whitespace) {
history_dirty = rl.add_history_entry(line.clone());
}
let (eval_kind, input) = match parse_command(line) {
ParsedCommand::EvalValue(input) => (EvalKind::Value, input),
ParsedCommand::EvalType(input) => (EvalKind::Type, input),
ParsedCommand::Quit => {
break;
}
ParsedCommand::Other => {
continue;
}
};
repl_ctx.send_line(input, eval_kind).unwrap();
if history_dirty {
if let Some(ref history_path) = history_path {
let _ = rl.save_history(&history_path);
}
}
match repl_ctx.receive_result() {
Ok(EvaledLine::EmptyInput) => {}
Ok(EvaledLine::Defs(bound_names)) => {
rl.set_helper(Some(ArretHelper::new(bound_names)));
println!("{}", defs_style.paint("defined"))
}
Ok(EvaledLine::ExprType(type_str)) => {
println!(
"{} {}",
expr_arrow_style.paint("=>"),
type_style.paint(type_str)
);
}
Ok(EvaledLine::ExprValue(evaled_expr)) => {
let EvaledExprValue {
value_str,
type_str,
type_is_literal,
} = evaled_expr;
if type_is_literal {
println!(
"{} {}",
expr_arrow_style.paint("=>"),
value_str,
);
} else {
println!(
"{} {}{} {}{}",
expr_arrow_style.paint("=>"),
type_brackets_style.paint("["),
value_str,
type_style.paint(type_str),
type_brackets_style.paint("]"),
);
}
}
Err(diagnostics) => {
emit_diagnostics_to_stderr(ccx.source_loader(), diagnostics);
}
}
}
Err(ReadlineError::Interrupted) | Err(ReadlineError::Eof) => break,
Err(other) => {
panic!("Readline error: {:?}", other);
}
}
}
}