mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-27 11:59:05 +00:00
fix socket connection problems
This commit is contained in:
parent
fa5bb4f615
commit
b76d63f9a5
6 changed files with 52 additions and 30 deletions
|
@ -74,13 +74,15 @@ impl fmt::Display for ErgMode {
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct DummyStdin {
|
pub struct DummyStdin {
|
||||||
|
pub name: String,
|
||||||
current_line: usize,
|
current_line: usize,
|
||||||
lines: Vec<String>,
|
lines: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DummyStdin {
|
impl DummyStdin {
|
||||||
pub fn new(lines: Vec<String>) -> Self {
|
pub fn new(name: String, lines: Vec<String>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
name,
|
||||||
current_line: 0,
|
current_line: 0,
|
||||||
lines,
|
lines,
|
||||||
}
|
}
|
||||||
|
@ -160,7 +162,8 @@ impl Input {
|
||||||
pub fn filename(&self) -> &str {
|
pub fn filename(&self) -> &str {
|
||||||
match self {
|
match self {
|
||||||
Self::File(filename) => filename.file_name().and_then(|f| f.to_str()).unwrap_or("_"),
|
Self::File(filename) => filename.file_name().and_then(|f| f.to_str()).unwrap_or("_"),
|
||||||
Self::REPL | Self::DummyREPL(_) | Self::Pipe(_) => "stdin",
|
Self::REPL | Self::Pipe(_) => "stdin",
|
||||||
|
Self::DummyREPL(stdin) => &stdin.name,
|
||||||
Self::Str(_) => "string",
|
Self::Str(_) => "string",
|
||||||
Self::Dummy => "dummy",
|
Self::Dummy => "dummy",
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
//! defines the compiler for Erg (ergc).
|
//! defines the compiler for Erg (ergc).
|
||||||
#![allow(clippy::large_enum_variant)]
|
#![allow(clippy::large_enum_variant)]
|
||||||
|
#![allow(clippy::result_large_err)]
|
||||||
extern crate erg_common;
|
extern crate erg_common;
|
||||||
pub extern crate erg_parser;
|
pub extern crate erg_parser;
|
||||||
|
|
||||||
|
|
30
src/dummy.rs
30
src/dummy.rs
|
@ -61,7 +61,8 @@ impl Runnable for DummyVM {
|
||||||
}
|
}
|
||||||
let port = find_available_port();
|
let port = find_available_port();
|
||||||
let code = include_str!("scripts/repl_server.py")
|
let code = include_str!("scripts/repl_server.py")
|
||||||
.replace("__PORT__", port.to_string().as_str());
|
.replace("__PORT__", port.to_string().as_str())
|
||||||
|
.replace("__MODULE__", &cfg.dump_filename());
|
||||||
spawn_py(cfg.py_command, &code);
|
spawn_py(cfg.py_command, &code);
|
||||||
let addr = SocketAddrV4::new(Ipv4Addr::LOCALHOST, port);
|
let addr = SocketAddrV4::new(Ipv4Addr::LOCALHOST, port);
|
||||||
if !cfg.quiet_repl {
|
if !cfg.quiet_repl {
|
||||||
|
@ -112,7 +113,7 @@ impl Runnable for DummyVM {
|
||||||
process::exit(1);
|
process::exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
remove_file("o.pyc").unwrap_or(());
|
remove_file(self.cfg().dump_pyc_filename()).unwrap_or(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,9 +143,10 @@ impl Runnable for DummyVM {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval(&mut self, src: String) -> Result<String, EvalErrors> {
|
fn eval(&mut self, src: String) -> Result<String, EvalErrors> {
|
||||||
|
let path = self.cfg().dump_pyc_filename();
|
||||||
let arti = self
|
let arti = self
|
||||||
.compiler
|
.compiler
|
||||||
.eval_compile_and_dump_as_pyc("o.pyc", src, "eval")
|
.eval_compile_and_dump_as_pyc(path, src, "eval")
|
||||||
.map_err(|eart| eart.errors)?;
|
.map_err(|eart| eart.errors)?;
|
||||||
let (last, warns) = (arti.object, arti.warns);
|
let (last, warns) = (arti.object, arti.warns);
|
||||||
let mut res = warns.to_string();
|
let mut res = warns.to_string();
|
||||||
|
@ -207,17 +209,23 @@ impl DummyVM {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
fn find_available_port() -> u16 {
|
||||||
|
require_free_port()
|
||||||
|
}
|
||||||
|
#[cfg(not(test))]
|
||||||
fn find_available_port() -> u16 {
|
fn find_available_port() -> u16 {
|
||||||
const DEFAULT_PORT: u16 = 8736;
|
const DEFAULT_PORT: u16 = 8736;
|
||||||
TcpListener::bind(SocketAddrV4::new(Ipv4Addr::LOCALHOST, DEFAULT_PORT))
|
TcpListener::bind(SocketAddrV4::new(Ipv4Addr::LOCALHOST, DEFAULT_PORT))
|
||||||
.is_ok()
|
.is_ok()
|
||||||
.then_some(DEFAULT_PORT)
|
.then_some(DEFAULT_PORT)
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(require_free_port)
|
||||||
// localhost:0 will bind to a free port
|
}
|
||||||
let socket = SocketAddrV4::new(Ipv4Addr::LOCALHOST, 0);
|
|
||||||
TcpListener::bind(socket)
|
fn require_free_port() -> u16 {
|
||||||
.and_then(|listener| listener.local_addr())
|
let socket = SocketAddrV4::new(Ipv4Addr::LOCALHOST, 0);
|
||||||
.map(|sock_addr| sock_addr.port())
|
TcpListener::bind(socket)
|
||||||
.expect("No free port found.")
|
.and_then(|listener| listener.local_addr())
|
||||||
})
|
.map(|sock_addr| sock_addr.port())
|
||||||
|
.expect("No free port found.")
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,9 +28,10 @@ while True:
|
||||||
__sys.stdout = __io.StringIO()
|
__sys.stdout = __io.StringIO()
|
||||||
try:
|
try:
|
||||||
if __already_loaded:
|
if __already_loaded:
|
||||||
__res = str(exec('__importlib.reload(o)'))
|
# __MODULE__ will be replaced with module name
|
||||||
|
__res = str(exec('__importlib.reload(__MODULE__)'))
|
||||||
else:
|
else:
|
||||||
__res = str(exec('import o'))
|
__res = str(exec('import __MODULE__'))
|
||||||
except SystemExit:
|
except SystemExit:
|
||||||
__client_socket.send('[Exception] SystemExit'.encode())
|
__client_socket.send('[Exception] SystemExit'.encode())
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -12,8 +12,8 @@ use erg_compiler::error::CompileErrors;
|
||||||
|
|
||||||
use erg::DummyVM;
|
use erg::DummyVM;
|
||||||
|
|
||||||
pub(crate) fn expect_repl_success(lines: Vec<String>) -> Result<(), ()> {
|
pub(crate) fn expect_repl_success(name: &'static str, lines: Vec<String>) -> Result<(), ()> {
|
||||||
match exec_repl(lines) {
|
match exec_repl(name, lines) {
|
||||||
Ok(ExitStatus::OK) => Ok(()),
|
Ok(ExitStatus::OK) => Ok(()),
|
||||||
Ok(stat) => {
|
Ok(stat) => {
|
||||||
println!("err: should succeed, but got: {stat:?}");
|
println!("err: should succeed, but got: {stat:?}");
|
||||||
|
@ -114,10 +114,10 @@ fn _exec_file(file_path: &'static str) -> Result<i32, CompileErrors> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// WARN: You must quit REPL manually (use `:exit`, `:quit` or call something shutdowns the interpreter)
|
/// WARN: You must quit REPL manually (use `:exit`, `:quit` or call something shutdowns the interpreter)
|
||||||
pub fn _exec_repl(lines: Vec<String>) -> Result<ExitStatus, CompileErrors> {
|
pub fn _exec_repl(name: &'static str, lines: Vec<String>) -> Result<ExitStatus, CompileErrors> {
|
||||||
println!("{GREEN}[test] exec dummy REPL: {lines:?}{RESET}");
|
println!("{GREEN}[test] exec dummy REPL: {lines:?}{RESET}");
|
||||||
let cfg = ErgConfig {
|
let cfg = ErgConfig {
|
||||||
input: Input::DummyREPL(DummyStdin::new(lines)),
|
input: Input::DummyREPL(DummyStdin::new(name.to_string(), lines)),
|
||||||
quiet_repl: true,
|
quiet_repl: true,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
@ -129,6 +129,9 @@ pub(crate) fn exec_file(file_path: &'static str) -> Result<i32, CompileErrors> {
|
||||||
exec_new_thread(move || _exec_file(file_path))
|
exec_new_thread(move || _exec_file(file_path))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn exec_repl(lines: Vec<String>) -> Result<ExitStatus, CompileErrors> {
|
pub(crate) fn exec_repl(
|
||||||
exec_new_thread(move || _exec_repl(lines))
|
name: &'static str,
|
||||||
|
lines: Vec<String>,
|
||||||
|
) -> Result<ExitStatus, CompileErrors> {
|
||||||
|
exec_new_thread(move || _exec_repl(name, lines))
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,17 +3,23 @@ use common::expect_repl_success;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn exec_repl_helloworld() -> Result<(), ()> {
|
fn exec_repl_helloworld() -> Result<(), ()> {
|
||||||
expect_repl_success(vec!["print! \"hello, world\"".into(), "exit()".into()])
|
expect_repl_success(
|
||||||
|
"repl_hello",
|
||||||
|
vec!["print! \"hello, world\"".into(), "exit()".into()],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn exec_repl_def_func() -> Result<(), ()> {
|
fn exec_repl_def_func() -> Result<(), ()> {
|
||||||
expect_repl_success(vec![
|
expect_repl_success(
|
||||||
"f i =".into(),
|
"repl_def",
|
||||||
" i + 1".into(),
|
vec![
|
||||||
"".into(),
|
"f i =".into(),
|
||||||
"x = f 2".into(),
|
" i + 1".into(),
|
||||||
"assert x == 3".into(),
|
"".into(),
|
||||||
"exit()".into(),
|
"x = f 2".into(),
|
||||||
])
|
"assert x == 3".into(),
|
||||||
|
"exit()".into(),
|
||||||
|
],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue