mirror of
https://github.com/erg-lang/erg.git
synced 2025-10-03 05:54:33 +00:00
Add py-command
option
This commit is contained in:
parent
765acceaf4
commit
216470b3a1
7 changed files with 69 additions and 28 deletions
|
@ -159,7 +159,8 @@ pub struct ErgConfig {
|
||||||
/// * 3: e.g. JIT compiling
|
/// * 3: e.g. JIT compiling
|
||||||
pub opt_level: u8,
|
pub opt_level: u8,
|
||||||
pub no_std: bool,
|
pub no_std: bool,
|
||||||
pub python_ver: Option<u32>,
|
pub py_magic_num: Option<u32>,
|
||||||
|
pub py_command: Option<&'static str>,
|
||||||
pub py_server_timeout: u64,
|
pub py_server_timeout: u64,
|
||||||
pub quiet_startup: bool,
|
pub quiet_startup: bool,
|
||||||
pub show_type: bool,
|
pub show_type: bool,
|
||||||
|
@ -183,7 +184,8 @@ impl Default for ErgConfig {
|
||||||
mode: "exec",
|
mode: "exec",
|
||||||
opt_level: 1,
|
opt_level: 1,
|
||||||
no_std: false,
|
no_std: false,
|
||||||
python_ver: None,
|
py_magic_num: None,
|
||||||
|
py_command: None,
|
||||||
py_server_timeout: 10,
|
py_server_timeout: 10,
|
||||||
quiet_startup: false,
|
quiet_startup: false,
|
||||||
show_type: false,
|
show_type: false,
|
||||||
|
@ -281,13 +283,21 @@ impl ErgConfig {
|
||||||
.parse::<u8>()
|
.parse::<u8>()
|
||||||
.expect("the value of `-o` is not a number");
|
.expect("the value of `-o` is not a number");
|
||||||
}
|
}
|
||||||
"-p" | "--py-ver" | "--python-version" => {
|
"--py-command" | "--python-command" => {
|
||||||
let py_ver = args
|
let py_command = args
|
||||||
.next()
|
.next()
|
||||||
.expect("the value of `-p` is not passed")
|
.expect("the value of `--py-command` is not passed")
|
||||||
|
.parse::<String>()
|
||||||
|
.expect("the value of `-py-command` is not a valid Python command");
|
||||||
|
cfg.py_command = Some(Box::leak(py_command.into_boxed_str()));
|
||||||
|
}
|
||||||
|
"--py-magic-num" | "--python-magic-number" => {
|
||||||
|
let py_magic_num = args
|
||||||
|
.next()
|
||||||
|
.expect("the value of `--py-magic-num` is not passed")
|
||||||
.parse::<u32>()
|
.parse::<u32>()
|
||||||
.expect("the value of `-p` is not a number");
|
.expect("the value of `--py-magic-num` is not a number");
|
||||||
cfg.python_ver = Some(py_ver);
|
cfg.py_magic_num = Some(py_magic_num);
|
||||||
}
|
}
|
||||||
"--py-server-timeout" => {
|
"--py-server-timeout" => {
|
||||||
cfg.py_server_timeout = args
|
cfg.py_server_timeout = args
|
||||||
|
|
|
@ -409,12 +409,12 @@ pub fn detect_magic_number() -> u32 {
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub struct PythonVersion {
|
pub struct PythonVersion {
|
||||||
pub major: u8,
|
pub major: u8,
|
||||||
pub minor: u8,
|
pub minor: Option<u8>,
|
||||||
pub micro: u8,
|
pub micro: Option<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PythonVersion {
|
impl PythonVersion {
|
||||||
pub const fn new(major: u8, minor: u8, micro: u8) -> Self {
|
pub const fn new(major: u8, minor: Option<u8>, micro: Option<u8>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
major,
|
major,
|
||||||
minor,
|
minor,
|
||||||
|
@ -429,7 +429,28 @@ impl PythonVersion {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn minor_is(&self, major: u8, minor: u8) -> bool {
|
pub fn minor_is(&self, major: u8, minor: u8) -> bool {
|
||||||
self.major == major && self.minor == minor
|
self.major == major && self.minor == Some(minor)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_command(&self) -> String {
|
||||||
|
match (self.minor, self.micro) {
|
||||||
|
(None, None) => format!("python{}", self.major),
|
||||||
|
(Some(minor), None) => format!("python{}.{minor}", self.major),
|
||||||
|
(None, Some(_)) => format!("python{}", self.major),
|
||||||
|
(Some(minor), Some(micro)) => format!("python{}.{}.{}", self.major, minor, micro),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::str::FromStr for PythonVersion {
|
||||||
|
type Err = String;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
let mut iter = s.split('.');
|
||||||
|
let major = iter.next().unwrap().parse::<u8>().unwrap_or(3);
|
||||||
|
let minor = iter.next().and_then(|i| i.parse::<u8>().ok());
|
||||||
|
let micro = iter.next().and_then(|i| i.parse::<u8>().ok());
|
||||||
|
Ok(Self::new(major, minor, micro))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -456,8 +477,8 @@ pub fn python_version() -> PythonVersion {
|
||||||
let s_version = String::from_utf8(out.stdout).unwrap();
|
let s_version = String::from_utf8(out.stdout).unwrap();
|
||||||
let mut iter = s_version.split(' ');
|
let mut iter = s_version.split(' ');
|
||||||
let major = iter.next().unwrap().parse().unwrap();
|
let major = iter.next().unwrap().parse().unwrap();
|
||||||
let minor = iter.next().unwrap().parse().unwrap();
|
let minor = iter.next().and_then(|i| i.parse::<u8>().ok());
|
||||||
let micro = iter.next().unwrap().trim_end().parse().unwrap();
|
let micro = iter.next().and_then(|i| i.trim_end().parse::<u8>().ok());
|
||||||
PythonVersion {
|
PythonVersion {
|
||||||
major,
|
major,
|
||||||
minor,
|
minor,
|
||||||
|
@ -466,16 +487,19 @@ pub fn python_version() -> PythonVersion {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// executes over a shell, cause `python` may not exist as an executable file (like pyenv)
|
/// executes over a shell, cause `python` may not exist as an executable file (like pyenv)
|
||||||
pub fn exec_pyc<S: Into<String>>(file: S) -> Option<i32> {
|
pub fn exec_pyc<S: Into<String>>(file: S, py_command: Option<&str>) -> Option<i32> {
|
||||||
|
let command = py_command
|
||||||
|
.map(ToString::to_string)
|
||||||
|
.unwrap_or_else(which_python);
|
||||||
let mut out = if cfg!(windows) {
|
let mut out = if cfg!(windows) {
|
||||||
Command::new("cmd")
|
Command::new("cmd")
|
||||||
.arg("/C")
|
.arg("/C")
|
||||||
.arg(which_python())
|
.arg(command)
|
||||||
.arg(&file.into())
|
.arg(&file.into())
|
||||||
.spawn()
|
.spawn()
|
||||||
.expect("cannot execute python")
|
.expect("cannot execute python")
|
||||||
} else {
|
} else {
|
||||||
let python_command = format!("{} {}", which_python(), file.into());
|
let python_command = format!("{command} {}", file.into());
|
||||||
Command::new("sh")
|
Command::new("sh")
|
||||||
.arg("-c")
|
.arg("-c")
|
||||||
.arg(python_command)
|
.arg(python_command)
|
||||||
|
@ -486,16 +510,19 @@ pub fn exec_pyc<S: Into<String>>(file: S) -> Option<i32> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// evaluates over a shell, cause `python` may not exist as an executable file (like pyenv)
|
/// evaluates over a shell, cause `python` may not exist as an executable file (like pyenv)
|
||||||
pub fn eval_pyc<S: Into<String>>(file: S) -> String {
|
pub fn eval_pyc<S: Into<String>>(file: S, py_command: Option<&str>) -> String {
|
||||||
|
let command = py_command
|
||||||
|
.map(ToString::to_string)
|
||||||
|
.unwrap_or_else(which_python);
|
||||||
let out = if cfg!(windows) {
|
let out = if cfg!(windows) {
|
||||||
Command::new("cmd")
|
Command::new("cmd")
|
||||||
.arg("/C")
|
.arg("/C")
|
||||||
.arg(which_python())
|
.arg(command)
|
||||||
.arg(&file.into())
|
.arg(&file.into())
|
||||||
.spawn()
|
.spawn()
|
||||||
.expect("cannot execute python")
|
.expect("cannot execute python")
|
||||||
} else {
|
} else {
|
||||||
let python_command = format!("{} {}", which_python(), file.into());
|
let python_command = format!("{command} {}", file.into());
|
||||||
Command::new("sh")
|
Command::new("sh")
|
||||||
.arg("-c")
|
.arg("-c")
|
||||||
.arg(python_command)
|
.arg(python_command)
|
||||||
|
|
|
@ -2054,7 +2054,10 @@ impl CodeGenerator {
|
||||||
self.write_arg(1u8);
|
self.write_arg(1u8);
|
||||||
self.stack_dec();
|
self.stack_dec();
|
||||||
self.emit_pop_top();
|
self.emit_pop_top();
|
||||||
let erg_std_mod = if self.py_version.le(&PythonVersion::new(3, 8, 10)) {
|
let erg_std_mod = if self
|
||||||
|
.py_version
|
||||||
|
.le(&PythonVersion::new(3, Some(8), Some(10)))
|
||||||
|
{
|
||||||
Identifier::public("_erg_std_prelude_old")
|
Identifier::public("_erg_std_prelude_old")
|
||||||
} else {
|
} else {
|
||||||
Identifier::public("_erg_std_prelude")
|
Identifier::public("_erg_std_prelude")
|
||||||
|
|
|
@ -152,7 +152,7 @@ impl Compiler {
|
||||||
mode: &str,
|
mode: &str,
|
||||||
) -> Result<(), CompileErrors> {
|
) -> Result<(), CompileErrors> {
|
||||||
let code = self.compile(src, mode)?;
|
let code = self.compile(src, mode)?;
|
||||||
code.dump_as_pyc(pyc_path, self.cfg.python_ver)
|
code.dump_as_pyc(pyc_path, self.cfg.py_magic_num)
|
||||||
.expect("failed to dump a .pyc file (maybe permission denied)");
|
.expect("failed to dump a .pyc file (maybe permission denied)");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -164,7 +164,7 @@ impl Compiler {
|
||||||
mode: &str,
|
mode: &str,
|
||||||
) -> Result<Option<Expr>, CompileErrors> {
|
) -> Result<Option<Expr>, CompileErrors> {
|
||||||
let (code, last) = self.eval_compile(src, mode)?;
|
let (code, last) = self.eval_compile(src, mode)?;
|
||||||
code.dump_as_pyc(pyc_path, self.cfg.python_ver)
|
code.dump_as_pyc(pyc_path, self.cfg.py_magic_num)
|
||||||
.expect("failed to dump a .pyc file (maybe permission denied)");
|
.expect("failed to dump a .pyc file (maybe permission denied)");
|
||||||
Ok(last)
|
Ok(last)
|
||||||
}
|
}
|
||||||
|
|
|
@ -305,16 +305,16 @@ impl CodeObj {
|
||||||
pub fn dump_as_pyc<P: AsRef<Path>>(
|
pub fn dump_as_pyc<P: AsRef<Path>>(
|
||||||
self,
|
self,
|
||||||
path: P,
|
path: P,
|
||||||
python_ver: Option<u32>,
|
py_magic_num: Option<u32>,
|
||||||
) -> std::io::Result<()> {
|
) -> std::io::Result<()> {
|
||||||
let mut file = File::create(path)?;
|
let mut file = File::create(path)?;
|
||||||
let mut bytes = Vec::with_capacity(16);
|
let mut bytes = Vec::with_capacity(16);
|
||||||
let python_ver = python_ver.unwrap_or_else(detect_magic_number);
|
let py_magic_num = py_magic_num.unwrap_or_else(detect_magic_number);
|
||||||
bytes.append(&mut get_magic_num_bytes(python_ver).to_vec());
|
bytes.append(&mut get_magic_num_bytes(py_magic_num).to_vec());
|
||||||
bytes.append(&mut vec![0; 4]); // padding
|
bytes.append(&mut vec![0; 4]); // padding
|
||||||
bytes.append(&mut get_timestamp_bytes().to_vec());
|
bytes.append(&mut get_timestamp_bytes().to_vec());
|
||||||
bytes.append(&mut vec![0; 4]); // padding
|
bytes.append(&mut vec![0; 4]); // padding
|
||||||
bytes.append(&mut self.into_bytes(python_ver));
|
bytes.append(&mut self.into_bytes(py_magic_num));
|
||||||
file.write_all(&bytes[..])?;
|
file.write_all(&bytes[..])?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,7 +110,7 @@ impl Runnable for DummyVM {
|
||||||
.replace(".er", ".pyc");
|
.replace(".er", ".pyc");
|
||||||
self.compiler
|
self.compiler
|
||||||
.compile_and_dump_as_pyc(&filename, self.input().read(), "exec")?;
|
.compile_and_dump_as_pyc(&filename, self.input().read(), "exec")?;
|
||||||
let code = exec_pyc(&filename);
|
let code = exec_pyc(&filename, self.cfg().py_command);
|
||||||
remove_file(&filename).unwrap();
|
remove_file(&filename).unwrap();
|
||||||
Ok(code.unwrap_or(1))
|
Ok(code.unwrap_or(1))
|
||||||
}
|
}
|
||||||
|
|
|
@ -192,7 +192,8 @@ fn expect_failure(file_path: &'static str, errs_len: usize) -> Result<(), ()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _exec_vm(file_path: &'static str) -> Result<i32, CompileErrors> {
|
fn _exec_vm(file_path: &'static str) -> Result<i32, CompileErrors> {
|
||||||
let cfg = ErgConfig::with_main_path(PathBuf::from(file_path));
|
let mut cfg = ErgConfig::with_main_path(PathBuf::from(file_path));
|
||||||
|
cfg.py_command = Some("python");
|
||||||
let mut vm = DummyVM::new(cfg);
|
let mut vm = DummyVM::new(cfg);
|
||||||
vm.exec()
|
vm.exec()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue