1use std::fs::remove_file;
2use std::io::{Read, Write};
3use std::net::{Ipv4Addr, SocketAddrV4, TcpListener, TcpStream};
4use std::process::{self, Command, Stdio};
5use std::thread::sleep;
6use std::time::Duration;
7
8use erg_common::config::ErgConfig;
9use erg_common::error::{ErrorDisplay, ErrorKind, MultiErrorDisplay};
10use erg_common::python_util::spawn_py;
11use erg_common::traits::{BlockKind, ExitStatus, New, Runnable};
12
13use erg_compiler::hir::Expr;
14use erg_compiler::ty::HasType;
15
16use erg_compiler::error::{CompileError, CompileErrors};
17use erg_compiler::Compiler;
18use erg_parser::ParserRunner;
19
20pub type EvalError = CompileError;
21pub type EvalErrors = CompileErrors;
22
23#[derive(Clone, Copy, PartialEq, Eq, Debug)]
25#[repr(u8)]
26enum Inst {
27 Print = 0x01,
29 Load = 0x02,
31 Exception = 0x03,
33 Initialize = 0x04,
35 Exit = 0x05,
37 Execute = 0x06,
39 Unknown = 0x00,
41}
42
43impl From<u8> for Inst {
44 fn from(v: u8) -> Inst {
45 match v {
46 0x01 => Inst::Print,
47 0x02 => Inst::Load,
48 0x03 => Inst::Exception,
49 0x04 => Inst::Initialize,
50 0x05 => Inst::Exit,
51 0x06 => Inst::Execute,
52 _ => Inst::Unknown,
53 }
54 }
55}
56
57#[derive(Debug, Clone)]
63struct Message {
64 inst: Inst,
65 size: u16,
66 data: Option<Vec<u8>>,
67}
68
69impl Message {
70 fn new(inst: Inst, data: Option<Vec<u8>>) -> Self {
71 let size = if let Some(d) = &data {
72 if d.len() > usize::from(u16::MAX) {
73 eprintln!("Warning: length truncated to 65535");
74 u16::MAX
75 } else {
76 d.len() as u16
77 }
78 } else {
79 0
80 };
81 Self { inst, size, data }
82 }
83
84 #[allow(unused)]
85 fn len(&self) -> usize {
86 self.size as usize
87 }
88}
89
90#[derive(Debug)]
91struct MessageStream<T: Read + Write> {
92 stream: T,
93}
94
95impl<T: Read + Write> MessageStream<T> {
96 fn new(stream: T) -> Self {
97 Self { stream }
98 }
99
100 fn send_msg(&mut self, msg: &Message) -> Result<(), std::io::Error> {
101 let mut write_buf = Vec::with_capacity(1024);
102 write_buf.extend((msg.inst as u8).to_be_bytes());
103 write_buf.extend((msg.size).to_be_bytes());
104 write_buf.extend_from_slice(&msg.data.clone().unwrap_or_default());
105
106 self.stream.write_all(&write_buf)?;
107
108 Ok(())
109 }
110
111 fn recv_msg(&mut self) -> Result<Message, std::io::Error> {
112 let mut inst_buf = [0; 1];
114 self.stream.read_exact(&mut inst_buf)?;
115
116 let inst: Inst = u8::from_be_bytes(inst_buf).into();
117
118 let mut size_buf = [0; 2];
120 self.stream.read_exact(&mut size_buf)?;
121
122 let data_size = u16::from_be_bytes(size_buf) as usize;
123
124 if data_size == 0 {
125 return Ok(Message::new(inst, None));
126 }
127
128 let mut data_buf = vec![0; data_size];
130 self.stream.read_exact(&mut data_buf)?;
131
132 Ok(Message::new(inst, Some(data_buf)))
133 }
134}
135
136#[test]
137fn test_message() {
138 use std::collections::VecDeque;
139
140 let inner = Box::<VecDeque<u8>>::default();
141 let mut stream = MessageStream::new(inner);
142
143 stream
145 .send_msg(&Message::new(
146 Inst::Print,
147 Some("hello".chars().map(|c| c as u8).collect()),
148 ))
149 .unwrap();
150 assert_eq!(
151 stream.stream.as_slices(),
152 (&[1, 0, 5, 104, 101, 108, 108, 111][..], &[][..])
153 );
154
155 stream.stream.push_front(0x41);
158 stream.stream.push_front(0x01);
160 stream.stream.push_front(0x00);
161 stream.stream.push_front(0x01);
163
164 let msg = stream.recv_msg().unwrap();
165 assert_eq!(msg.inst, Inst::Print);
166 assert_eq!(msg.len(), 1);
167 assert_eq!(std::str::from_utf8(&msg.data.unwrap()).unwrap(), "A");
168}
169
170fn find_available_port() -> u16 {
171 let socket = SocketAddrV4::new(Ipv4Addr::LOCALHOST, 0);
172 TcpListener::bind(socket)
173 .and_then(|listener| listener.local_addr())
174 .map(|sock_addr| sock_addr.port())
175 .expect("No free port found.")
176}
177
178#[derive(Debug)]
182pub struct DummyVM {
183 compiler: Compiler,
184 stream: Option<MessageStream<TcpStream>>,
185}
186
187impl Default for DummyVM {
188 fn default() -> Self {
189 Self::new(ErgConfig::default())
190 }
191}
192
193impl Drop for DummyVM {
194 fn drop(&mut self) {
195 self.finish();
196 }
197}
198
199impl New for DummyVM {
200 fn new(cfg: ErgConfig) -> Self {
201 let stream = if cfg.input.is_repl() {
202 if !cfg.quiet_repl {
203 println!("Starting the REPL server...");
204 }
205 let port = find_available_port();
206 let code = include_str!("scripts/repl_server.py")
207 .replace("__PORT__", port.to_string().as_str())
208 .replace("__MODULE__", &cfg.dump_filename().replace('/', "."));
209 #[allow(clippy::zombie_processes)]
210 let _ = spawn_py(cfg.py_command, &code);
211 let addr = SocketAddrV4::new(Ipv4Addr::LOCALHOST, port);
212 if !cfg.quiet_repl {
213 println!("Connecting to the REPL server...");
214 }
215 loop {
216 match TcpStream::connect(addr) {
217 Ok(stream) => {
218 stream
219 .set_read_timeout(Some(Duration::from_secs(cfg.py_server_timeout)))
220 .unwrap();
221 break Some(MessageStream::new(stream));
222 }
223 Err(_) => {
224 if !cfg.quiet_repl {
225 println!("Retrying to connect to the REPL server...");
226 }
227 sleep(Duration::from_millis(500));
228 continue;
229 }
230 }
231 }
232 } else {
233 None
234 };
235 Self {
236 compiler: Compiler::new(cfg),
237 stream,
238 }
239 }
240}
241
242impl Runnable for DummyVM {
243 type Err = EvalError;
244 type Errs = EvalErrors;
245 const NAME: &'static str = "Erg interpreter";
246
247 #[inline]
248 fn cfg(&self) -> &ErgConfig {
249 &self.compiler.cfg
250 }
251 #[inline]
252 fn cfg_mut(&mut self) -> &mut ErgConfig {
253 &mut self.compiler.cfg
254 }
255
256 fn finish(&mut self) {
257 if let Some(stream) = &mut self.stream {
258 if let Err(err) = stream.send_msg(&Message::new(Inst::Exit, None)) {
260 eprintln!("Write error: {err}");
261 process::exit(1);
262 }
263
264 match stream.recv_msg() {
266 Result::Ok(msg) => {
267 if msg.inst == Inst::Exit && !self.cfg().quiet_repl {
268 println!("The REPL server is closed.");
269 }
270 }
271 Result::Err(err) => {
272 eprintln!("Read error: {err}");
273 process::exit(1);
274 }
275 }
276
277 remove_file(self.cfg().dump_pyc_filename()).unwrap_or(());
278 }
279 }
280
281 fn initialize(&mut self) {
282 self.compiler.initialize();
283 }
284
285 fn clear(&mut self) {
286 self.compiler.clear();
287 }
288
289 fn exec(&mut self) -> Result<ExitStatus, Self::Errs> {
290 let src = self.cfg_mut().input.read();
291 let art = self.compiler.compile(src, "exec").map_err(|eart| {
292 eart.warns.write_all_to(&mut self.cfg_mut().output);
293 eart.errors
294 })?;
295 art.warns.write_all_to(&mut self.cfg_mut().output);
296 let stat = art.object.exec(self.cfg()).expect("failed to execute");
297 let stat = ExitStatus::new(stat.code().unwrap_or(0), art.warns.len(), 0);
298 Ok(stat)
299 }
300
301 fn eval(&mut self, src: String) -> Result<String, EvalErrors> {
302 let arti = self
303 .compiler
304 .eval_compile(src, "eval")
305 .map_err(|eart| eart.errors)?;
306 let ((code, last), warns) = (arti.object, arti.warns);
307 let mut res = warns.to_string();
308
309 macro_rules! err_handle {
310 () => {{
311 self.finish();
312 process::exit(1);
313 }};
314 ($hint:expr $(,$args:expr),* $(,)?) => {{
315 self.finish();
316 eprintln!($hint, $($args)*);
317 process::exit(1);
318 }};
319 }
320
321 if let Err(err) = self.stream.as_mut().unwrap().send_msg(&Message::new(
323 Inst::Execute,
324 Some(
325 code.into_script(self.compiler.cfg.py_magic_num)
326 .into_bytes(),
327 ),
328 )) {
329 err_handle!("Sending error: {err}");
330 };
331
332 let data = match self.stream.as_mut().unwrap().recv_msg() {
334 Result::Ok(msg) => {
335 let s = match msg.inst {
336 Inst::Exception => {
337 debug_assert!(
338 std::str::from_utf8(msg.data.as_ref().unwrap()) == Ok("SystemExit")
339 );
340 return Err(EvalErrors::from(EvalError::system_exit()));
341 }
342 Inst::Initialize => {
343 self.compiler.initialize_generator();
344 String::from_utf8(msg.data.unwrap_or_default())
345 }
346 Inst::Print => String::from_utf8(msg.data.unwrap_or_default()),
347 Inst::Exit => err_handle!("Receiving inst {:?} from server", msg.inst),
348 Inst::Load | Inst::Execute | Inst::Unknown => {
350 err_handle!("Receiving unexpected inst {:?} from server", msg.inst)
351 }
352 };
353
354 if let Ok(ss) = s {
355 ss
356 } else {
357 err_handle!("Failed to parse server response data, error: {:?}", s.err());
358 }
359 }
360 Result::Err(err) => err_handle!("Received an error: {err}"),
361 };
362
363 res.push_str(&data);
364 if res.ends_with("None") {
366 res.truncate(res.len() - 5);
367 }
368
369 if self.cfg().show_type {
370 res.push_str(": ");
371 res.push_str(
372 &last
373 .as_ref()
374 .map(|last| last.t())
375 .unwrap_or_default()
376 .to_string(),
377 );
378 if let Some(Expr::Def(def)) = last {
379 res.push_str(&format!(" ({})", def.sig.ident()));
380 }
381 }
382 Ok(res)
383 }
384
385 fn expect_block(&self, src: &str) -> BlockKind {
386 let mut parser = ParserRunner::new(self.cfg().clone());
387 match parser.eval(src.to_string()) {
388 Err(errs) => {
389 let kind = errs
390 .iter()
391 .filter(|e| e.core().kind == ErrorKind::ExpectNextLine)
392 .map(|e| {
393 let msg = e.core().sub_messages.last().unwrap();
394 msg.get_msg().first().unwrap().to_owned()
396 })
397 .next();
398 if let Some(kind) = kind {
399 return BlockKind::from(kind.as_str());
400 }
401 if errs
402 .iter()
403 .any(|err| err.core.main_message.contains("\"\"\""))
404 {
405 return BlockKind::MultiLineStr;
406 }
407 BlockKind::Error
408 }
409 Ok(_) => {
410 if src.contains("Class") {
411 return BlockKind::ClassDef;
412 }
413 BlockKind::None
414 }
415 }
416 }
417}
418
419impl DummyVM {
420 pub fn new(cfg: ErgConfig) -> Self {
421 New::new(cfg)
422 }
423
424 pub fn exec(&mut self) -> Result<ExitStatus, EvalErrors> {
426 Runnable::exec(self)
427 }
428
429 pub fn eval(&mut self, src: String) -> Result<String, EvalErrors> {
431 Runnable::eval(self, src)
432 }
433}
434
435#[derive(Debug, Default)]
436pub struct PackageManagerRunner {}
437
438impl PackageManagerRunner {
439 pub fn new() -> Self {
440 Self {}
441 }
442
443 pub fn run(cfg: ErgConfig) -> ExitStatus {
444 if Command::new("poise").arg("--version").output().is_err() {
445 eprintln!("Error: poise is not installed. Please install using ergup or manually from the repository (https://github.com/erg-lang/poise).");
446 return ExitStatus::ERR1;
447 }
448 match Command::new("poise")
449 .stdin(Stdio::inherit())
450 .stdout(Stdio::inherit())
451 .stderr(Stdio::inherit())
452 .args(cfg.runtime_args.as_ref())
453 .output()
454 {
455 Ok(out) => ExitStatus::new(out.status.code().unwrap_or(0), 0, 0),
456 Err(err) => {
457 eprintln!("Error: {}", err);
458 ExitStatus::ERR1
459 }
460 }
461 }
462}