erg/
dummy.rs

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/// The instructions for communication between the client and the server.
24#[derive(Clone, Copy, PartialEq, Eq, Debug)]
25#[repr(u8)]
26enum Inst {
27    /// Send from server to client. Informs the client to print data.
28    Print = 0x01,
29    /// Send from client to server. Informs the REPL server that the executable .pyc file has been written out and is ready for evaluation.
30    Load = 0x02,
31    /// Send from server to client. Represents an exception.
32    Exception = 0x03,
33    /// Send from server to client. Tells the code generator to initialize due to an error.
34    Initialize = 0x04,
35    /// Informs that the connection is to be / should be terminated.
36    Exit = 0x05,
37    /// Send from client to server. Let the server to execute the code.
38    Execute = 0x06,
39    /// Informs that it is not a supported instruction.
40    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/// -------------------------------
58/// | ins    | size    | data
59/// -------------------------------
60/// | 1 byte | 2 bytes | n bytes
61/// -------------------------------
62#[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        // read instruction, 1 byte
113        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        // read size, 2 bytes
119        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        // read data
129        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    // test send_msg with data
144    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    // test recv_msg
156    // data field, 'A' => hex is 0x41
157    stream.stream.push_front(0x41);
158    // size field
159    stream.stream.push_front(0x01);
160    stream.stream.push_front(0x00);
161    // inst field
162    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/// Open the Python interpreter as a server and act as an Erg interpreter by mediating communication
179///
180/// Pythonインタープリタをサーバーとして開き、通信を仲介することでErgインタープリタとして振る舞う
181#[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            // send exit to server
259            if let Err(err) = stream.send_msg(&Message::new(Inst::Exit, None)) {
260                eprintln!("Write error: {err}");
261                process::exit(1);
262            }
263
264            // wait server exit
265            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        // Tell the REPL server to execute the code
322        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        // receive data from server
333        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                    // `load` can only be sent from the client to the server
349                    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 the result of an expression is None, it will not be displayed in the REPL.
365        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                        // ExpectNextLine error must have msg otherwise it's a bug
395                        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    /// Execute the script specified in the configuration.
425    pub fn exec(&mut self) -> Result<ExitStatus, EvalErrors> {
426        Runnable::exec(self)
427    }
428
429    /// Evaluates code passed as a string.
430    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}