1use std::env::current_dir;
10use std::ffi::OsString;
11use std::fs::create_dir_all;
12use std::io::Cursor;
13use std::path::PathBuf;
14use std::sync::Arc;
15use std::sync::RwLock;
16#[cfg(feature = "plot")]
17use std::thread;
18use rustyline::error::ReadlineError;
19use rustyline::DefaultEditor;
20#[cfg(feature = "plot")]
21use crate::winit::event_loop::ControlFlow;
22#[cfg(feature = "plot")]
23use crate::winit::event_loop::EventLoop;
24use crate::doc::*;
25use crate::env::*;
26use crate::error::*;
27use crate::interp::*;
28use crate::intr::*;
29use crate::lexer::*;
30use crate::mod_node::*;
31use crate::parser::*;
32#[cfg(feature = "plot")]
33use crate::plot::*;
34use crate::utils::*;
35use crate::value::*;
36
37#[cfg(feature = "plot")]
38fn run_plotter_app<F>(are_plotter_windows: bool, f: F) -> Option<i32>
39 where F: FnOnce(Option<EventLoopProxy>) -> Option<i32> + Send + 'static
40{
41 if are_plotter_windows {
42 let event_loop = match EventLoop::<PlotterAppEvent>::with_user_event().build() {
43 Ok(tmp_event_loop) => tmp_event_loop,
44 Err(err) => {
45 eprintln!("{}", err);
46 return Some(1);
47 },
48 };
49 let event_loop_proxy = event_loop.create_proxy();
50 let thr = thread::spawn(move || f(Some(event_loop_proxy)));
51 event_loop.set_control_flow(ControlFlow::Poll);
52 event_loop.set_control_flow(ControlFlow::Wait);
53 let mut plotter_app = PlotterApp::new(&event_loop);
54 match event_loop.run_app(&mut plotter_app) {
55 Ok(()) => (),
56 Err(err) => {
57 eprintln!("{}", err);
58 return Some(1);
59 },
60 }
61 match thr.join() {
62 Ok(res) => res,
63 Err(_) => {
64 eprintln!("can't join thread");
65 Some(1)
66 },
67 }
68 } else {
69 f(None)
70 }
71}
72
73#[cfg(feature = "plot")]
74fn quit_from_plotter_app(env: &Env) -> bool
75{
76 match rw_lock_read(env.shared_env()) {
77 Ok(shared_env_g) => {
78 match shared_env_g.event_loop_proxy() {
79 Some(event_loop_proxy) => {
80 match event_loop_proxy.send_event(PlotterAppEvent::Quit) {
81 Ok(()) => true,
82 Err(err) => {
83 eprintln!("{}", err);
84 false
85 },
86 }
87 },
88 None => true,
89 }
90 },
91 Err(err) => {
92 eprint_error(&err);
93 false
94 },
95 }
96}
97
98#[cfg(not(feature = "plot"))]
99fn run_plotter_app<F>(_are_plotter_windows: bool, f: F) -> Option<i32>
100 where F: FnOnce(Option<EventLoopProxy>) -> Option<i32> + Send + Sync + 'static
101{ f(None) }
102
103#[cfg(not(feature = "plot"))]
104fn quit_from_plotter_app(_env: &Env) -> bool
105{ true }
106
107fn non_interactive_main_loop(path: String, args: Vec<String>, root_mod: Arc<RwLock<ModNode<Value, ()>>>, lib_path: OsString, doc_path: OsString, is_ctrl_c_intr_checker: bool, are_plotter_windows: bool) -> Option<i32>
108{
109 run_plotter_app(are_plotter_windows, move |event_loop_proxy| {
110 let intr_checker: Arc<dyn IntrCheck + Send + Sync> = if is_ctrl_c_intr_checker {
111 match CtrlCIntrChecker::initialize() {
112 Ok(()) => (),
113 Err(err) => {
114 eprint_error(&err);
115 return Some(1);
116 },
117 }
118 Arc::new(CtrlCIntrChecker::new())
119 } else {
120 Arc::new(EmptyIntrChecker::new())
121 };
122 let shared_env = SharedEnv::new_with_intr_checker_and_event_loop_proxy(lib_path, doc_path, args, intr_checker, event_loop_proxy);
123 let mut env = Env::new_with_script_dir_and_domain_and_shared_env(root_mod, PathBuf::from("."), None, Arc::new(RwLock::new(shared_env)));
124 let mut interp = Interp::new();
125 let res = match parse(path) {
126 Ok(tree) => {
127 match interp.interpret(&mut env, &tree) {
128 Ok(()) => None,
129 Err(Error::Stop(Stop::ErrorPropagation)) => {
130 eprintln!("{}", interp.ret_value());
131 Some(1)
132 },
133 Err(Error::Stop(Stop::Quit)) => None,
134 Err(Error::Stop(Stop::Exit(code))) => Some(code),
135 Err(err @ Error::Intr) => {
136 eprint_error(&err);
137 Some(1)
138 },
139 Err(err) => {
140 eprint_error_with_stack_trace(&err, interp.stack_trace());
141 Some(1)
142 },
143 }
144 },
145 Err(err) => {
146 eprint_error(&err);
147 Some(1)
148 },
149 };
150 if !quit_from_plotter_app(&env) {
151 return Some(1);
152 }
153 res
154 })
155}
156
157fn interactive_main_loop(args: Vec<String>, history_file: PathBuf, root_mod: Arc<RwLock<ModNode<Value, ()>>>, lib_path: OsString, doc_path: OsString, is_ctrl_c_intr_checker: bool, are_plotter_windows: bool) -> Option<i32>
158{
159 run_plotter_app(are_plotter_windows, move |event_loop_proxy| {
160 let intr_checker: Arc<dyn IntrCheck + Send + Sync> = if is_ctrl_c_intr_checker {
161 match CtrlCIntrChecker::initialize() {
162 Ok(()) => (),
163 Err(err) => {
164 eprint_error(&err);
165 return Some(1);
166 },
167 }
168 Arc::new(CtrlCIntrChecker::new())
169 } else {
170 Arc::new(EmptyIntrChecker::new())
171 };
172 let shared_env = SharedEnv::new_with_intr_checker_and_event_loop_proxy(lib_path, doc_path, args, intr_checker, event_loop_proxy);
173 let mut env = Env::new_with_script_dir_and_domain_and_shared_env(root_mod, PathBuf::from("."), None, Arc::new(RwLock::new(shared_env)));
174 let mut interp = Interp::new();
175 let mut editor = match DefaultEditor::new() {
176 Ok(tmp_editor) => tmp_editor,
177 Err(err) => {
178 eprintln!("{}", err);
179 return Some(1);
180 },
181 };
182 let mut real_history_file = match current_dir() {
183 Ok(dir) => dir,
184 Err(err) => {
185 eprintln!("{}", err);
186 return Some(1);
187 },
188 };
189 real_history_file.push(history_file.as_path());
190 let _res = editor.load_history(real_history_file.as_path());
191 let mut line_num = 1u64;
192 let mut res: Option<i32> = None;
193 loop {
194 match editor.readline(format!("unlab-gpu:{}> ", line_num).as_str()) {
195 Ok(line) => {
196 match editor.add_history_entry(line.as_str()) {
197 Ok(_) => (),
198 Err(err) => {
199 eprintln!("{}", err);
200 return Some(1);
201 },
202 }
203 let mut new_line_num = line_num;
204 let mut lines = line.clone();
205 lines.push('\n');
206 new_line_num += 1;
207 let tree = loop {
208 let mut cursor = Cursor::new(lines.as_str());
209 let mut lexer = Lexer::new_with_line(Arc::new(String::from("(stdin)")), &mut cursor, line_num);
210 let parser_path = lexer.path().clone();
211 let tokens: &mut dyn DocIterator<Item = Result<(Token, Pos)>> = &mut lexer;
212 let mut parser = Parser::new(parser_path, tokens);
213 match parser.parse() {
214 Ok(tree) => break Some(tree),
215 Err(err @ Error::ParserEof(_, ParserEofFlag::Repetition)) => {
216 match editor.readline("> ") {
217 Ok(next_line) => {
218 match editor.add_history_entry(next_line.as_str()) {
219 Ok(_) => (),
220 Err(err) => {
221 eprintln!("{}", err);
222 return Some(1);
223 },
224 }
225 lines.push_str(next_line.as_str());
226 lines.push('\n');
227 new_line_num += 1;
228 },
229 Err(ReadlineError::Interrupted) => (),
230 Err(ReadlineError::Eof) => {
231 eprint_error(&err);
232 break None;
233 },
234 Err(err) => {
235 eprintln!("{}", err);
236 return Some(1);
237 },
238 }
239 },
240 Err(err) => {
241 eprint_error(&err);
242 break None;
243 },
244 }
245 };
246 line_num = new_line_num;
247 if is_ctrl_c_intr_checker {
248 CtrlCIntrChecker::reset();
249 }
250 match tree {
251 Some(tree) => {
252 match interp.interpret(&mut env, &tree) {
253 Ok(()) => (),
254 Err(Error::Stop(Stop::ErrorPropagation)) => eprintln!("{}", interp.ret_value()),
255 Err(Error::Stop(Stop::Quit)) => break,
256 Err(Error::Stop(Stop::Exit(code))) => {
257 res = Some(code);
258 break;
259 },
260 Err(err @ Error::Intr) => eprint_error(&err),
261 Err(err) => eprint_error_with_stack_trace(&err, interp.stack_trace()),
262 }
263 interp.clear_stack_trace();
264 },
265 None => (),
266 }
267 },
268 Err(ReadlineError::Interrupted) => (),
269 Err(ReadlineError::Eof) => break,
270 Err(err) => {
271 eprintln!("{}", err);
272 return Some(1);
273 },
274 }
275 }
276 interp.clear_stack_trace();
277 let mut real_history_dir = real_history_file.clone();
278 real_history_dir.pop();
279 if real_history_dir != PathBuf::from("") {
280 match create_dir_all(real_history_dir.as_path()) {
281 Ok(()) => (),
282 Err(err) => {
283 eprintln!("{}", err);
284 return Some(1);
285 },
286 }
287 }
288 match editor.save_history(real_history_file.as_path()) {
289 Ok(()) => (),
290 Err(err) => {
291 eprintln!("{}", err);
292 return Some(1);
293 },
294 }
295 if !quit_from_plotter_app(&env) {
296 return Some(1);
297 }
298 res
299 })
300}
301
302pub fn main_loop(path: Option<String>, args: Vec<String>, history_file: PathBuf, root_mod: Arc<RwLock<ModNode<Value, ()>>>, lib_path: OsString, doc_path: OsString, is_ctrl_c_intr_checker: bool, are_plotter_windows: bool) -> Option<i32>
311{
312 match path {
313 Some(path) => non_interactive_main_loop(path, args, root_mod, lib_path, doc_path, is_ctrl_c_intr_checker, are_plotter_windows),
314 None => interactive_main_loop(args, history_file, root_mod, lib_path, doc_path, is_ctrl_c_intr_checker, are_plotter_windows),
315 }
316}