mirror of
https://github.com/erg-lang/erg.git
synced 2025-08-04 10:49:54 +00:00
commit
493492d0db
9 changed files with 110 additions and 72 deletions
|
@ -12,6 +12,7 @@ use std::str::FromStr;
|
|||
use crate::help_messages::{command_message, mode_message};
|
||||
use crate::normalize_path;
|
||||
use crate::python_util::{detect_magic_number, get_python_version, PythonVersion};
|
||||
use crate::random::random;
|
||||
use crate::serialize::{get_magic_num_from_bytes, get_ver_from_magic_num};
|
||||
use crate::stdin::GLOBAL_STDIN;
|
||||
use crate::{power_assert, read_file};
|
||||
|
@ -111,18 +112,30 @@ impl DummyStdin {
|
|||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum Input {
|
||||
File(PathBuf),
|
||||
REPL,
|
||||
REPL(u64),
|
||||
DummyREPL(DummyStdin),
|
||||
/// same content as cfg.command
|
||||
Pipe(String),
|
||||
Pipe(u64, String),
|
||||
/// from command option | eval
|
||||
Str(String),
|
||||
Str(u64, String),
|
||||
Dummy,
|
||||
}
|
||||
|
||||
impl Input {
|
||||
pub fn is_repl(&self) -> bool {
|
||||
matches!(self, Input::REPL | Input::DummyREPL(_))
|
||||
pub const fn is_repl(&self) -> bool {
|
||||
matches!(self, Input::REPL(_) | Input::DummyREPL(_))
|
||||
}
|
||||
|
||||
pub fn pipe(src: String) -> Self {
|
||||
Self::Pipe(random(), src)
|
||||
}
|
||||
|
||||
pub fn str(src: String) -> Self {
|
||||
Self::Str(random(), src)
|
||||
}
|
||||
|
||||
pub fn repl() -> Self {
|
||||
Self::REPL(random())
|
||||
}
|
||||
|
||||
pub fn path(&self) -> Option<&Path> {
|
||||
|
@ -132,40 +145,57 @@ impl Input {
|
|||
}
|
||||
}
|
||||
|
||||
pub const fn id(&self) -> u64 {
|
||||
match self {
|
||||
Input::File(_) | Input::DummyREPL(_) | Input::Dummy => 0,
|
||||
Input::REPL(id) | Input::Pipe(id, _) | Input::Str(id, _) => *id,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enclosed_name(&self) -> &str {
|
||||
match self {
|
||||
Self::File(filename) => filename.to_str().unwrap_or("_"),
|
||||
Self::REPL | Self::DummyREPL(_) | Self::Pipe(_) => "<stdin>",
|
||||
Self::Str(_) => "<string>",
|
||||
Self::REPL(_) | Self::DummyREPL(_) | Self::Pipe(_, _) => "<stdin>",
|
||||
Self::Str(_, _) => "<string>",
|
||||
Self::Dummy => "<dummy>",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn full_path(&self) -> &str {
|
||||
pub fn full_path(&self) -> PathBuf {
|
||||
match self {
|
||||
Self::File(filename) => filename.to_str().unwrap_or("_"),
|
||||
Self::REPL | Self::DummyREPL(_) | Self::Pipe(_) => "stdin",
|
||||
Self::Str(_) => "string",
|
||||
Self::Dummy => "dummy",
|
||||
Self::File(filename) => filename.clone(),
|
||||
Self::REPL(id) | Self::Pipe(id, _) => PathBuf::from(format!("stdin_{id}")),
|
||||
Self::DummyREPL(dummy) => PathBuf::from(format!("stdin_{}", dummy.name)),
|
||||
Self::Str(id, _) => PathBuf::from(format!("string_{id}")),
|
||||
Self::Dummy => PathBuf::from("dummy"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn file_stem(&self) -> &str {
|
||||
pub fn file_stem(&self) -> String {
|
||||
match self {
|
||||
Self::File(filename) => filename.file_stem().and_then(|f| f.to_str()).unwrap_or("_"),
|
||||
Self::REPL | Self::DummyREPL(_) | Self::Pipe(_) => "stdin",
|
||||
Self::Str(_) => "string",
|
||||
Self::Dummy => "dummy",
|
||||
Self::File(filename) => filename
|
||||
.file_stem()
|
||||
.and_then(|f| f.to_str())
|
||||
.unwrap_or("_")
|
||||
.to_string(),
|
||||
Self::REPL(id) | Self::Pipe(id, _) => format!("stdin_{id}"),
|
||||
Self::DummyREPL(stdin) => format!("stdin_{}", stdin.name),
|
||||
Self::Str(id, _) => format!("string_{id}"),
|
||||
Self::Dummy => "dummy".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn filename(&self) -> &str {
|
||||
pub fn filename(&self) -> String {
|
||||
match self {
|
||||
Self::File(filename) => filename.file_name().and_then(|f| f.to_str()).unwrap_or("_"),
|
||||
Self::REPL | Self::Pipe(_) => "stdin",
|
||||
Self::DummyREPL(stdin) => &stdin.name,
|
||||
Self::Str(_) => "string",
|
||||
Self::Dummy => "dummy",
|
||||
Self::File(filename) => filename
|
||||
.file_name()
|
||||
.and_then(|f| f.to_str())
|
||||
.unwrap_or("_")
|
||||
.to_string(),
|
||||
Self::REPL(id) | Self::Pipe(id, _) => format!("stdin_{id}"),
|
||||
Self::DummyREPL(stdin) => format!("stdin_{}", stdin.name),
|
||||
Self::Str(id, _) => format!("string_{id}"),
|
||||
Self::Dummy => "dummy".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -193,8 +223,8 @@ impl Input {
|
|||
}
|
||||
}
|
||||
}
|
||||
Self::Pipe(s) | Self::Str(s) => s.clone(),
|
||||
Self::REPL => GLOBAL_STDIN.read(),
|
||||
Self::Pipe(_, s) | Self::Str(_, s) => s.clone(),
|
||||
Self::REPL(_) => GLOBAL_STDIN.read(),
|
||||
Self::DummyREPL(dummy) => dummy.read_line().unwrap_or_default(),
|
||||
Self::Dummy => panic!("cannot read from a dummy file"),
|
||||
}
|
||||
|
@ -224,8 +254,8 @@ impl Input {
|
|||
}
|
||||
}
|
||||
}
|
||||
Self::Pipe(s) | Self::Str(s) => s.clone(),
|
||||
Self::REPL => GLOBAL_STDIN.read(),
|
||||
Self::Pipe(_, s) | Self::Str(_, s) => s.clone(),
|
||||
Self::REPL(_) => GLOBAL_STDIN.read(),
|
||||
Self::Dummy | Self::DummyREPL(_) => panic!("cannot read from a dummy file"),
|
||||
}
|
||||
}
|
||||
|
@ -244,12 +274,12 @@ impl Input {
|
|||
}
|
||||
Err(_) => vec!["<file not found>".into()],
|
||||
},
|
||||
Self::Pipe(s) | Self::Str(s) => s.split('\n').collect::<Vec<_>>()
|
||||
Self::Pipe(_, s) | Self::Str(_, s) => s.split('\n').collect::<Vec<_>>()
|
||||
[ln_begin - 1..=ln_end - 1]
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect(),
|
||||
Self::REPL => GLOBAL_STDIN.reread_lines(ln_begin, ln_end),
|
||||
Self::REPL(_) => GLOBAL_STDIN.reread_lines(ln_begin, ln_end),
|
||||
Self::DummyREPL(dummy) => dummy.reread_lines(ln_begin, ln_end),
|
||||
Self::Dummy => panic!("cannot read lines from a dummy file"),
|
||||
}
|
||||
|
@ -258,8 +288,8 @@ impl Input {
|
|||
pub fn reread(&self) -> String {
|
||||
match self {
|
||||
Self::File(_filename) => todo!(),
|
||||
Self::Pipe(s) | Self::Str(s) => s.clone(),
|
||||
Self::REPL => GLOBAL_STDIN.reread().trim_end().to_owned(),
|
||||
Self::Pipe(_, s) | Self::Str(_, s) => s.clone(),
|
||||
Self::REPL(_) => GLOBAL_STDIN.reread().trim_end().to_owned(),
|
||||
Self::DummyREPL(dummy) => dummy.reread().unwrap_or_default(),
|
||||
Self::Dummy => panic!("cannot read from a dummy file"),
|
||||
}
|
||||
|
@ -366,7 +396,7 @@ impl Default for ErgConfig {
|
|||
py_server_timeout: 10,
|
||||
quiet_repl: false,
|
||||
show_type: false,
|
||||
input: Input::REPL,
|
||||
input: Input::repl(),
|
||||
output_dir: None,
|
||||
module: "<module>",
|
||||
verbose: 1,
|
||||
|
@ -393,11 +423,11 @@ impl ErgConfig {
|
|||
self.clone()
|
||||
}
|
||||
|
||||
pub fn dump_path(&self) -> String {
|
||||
pub fn dump_path(&self) -> PathBuf {
|
||||
if let Some(output) = &self.output_dir {
|
||||
format!("{output}/{}", self.input.filename())
|
||||
PathBuf::from(format!("{output}/{}", self.input.filename()))
|
||||
} else {
|
||||
self.input.full_path().to_string()
|
||||
self.input.full_path()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -405,17 +435,14 @@ impl ErgConfig {
|
|||
if let Some(output) = &self.output_dir {
|
||||
format!("{output}/{}", self.input.filename())
|
||||
} else {
|
||||
self.input.filename().to_string()
|
||||
self.input.filename()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dump_pyc_path(&self) -> String {
|
||||
let dump_path = self.dump_path();
|
||||
if dump_path.ends_with(".er") {
|
||||
dump_path.replace(".er", ".pyc")
|
||||
} else {
|
||||
dump_path + ".pyc"
|
||||
}
|
||||
pub fn dump_pyc_path(&self) -> PathBuf {
|
||||
let mut dump_path = self.dump_path();
|
||||
dump_path.set_extension(".pyc");
|
||||
dump_path
|
||||
}
|
||||
|
||||
pub fn dump_pyc_filename(&self) -> String {
|
||||
|
@ -450,7 +477,7 @@ impl ErgConfig {
|
|||
break;
|
||||
}
|
||||
"-c" | "--code" => {
|
||||
cfg.input = Input::Str(args.next().expect("the value of `-c` is not passed"));
|
||||
cfg.input = Input::str(args.next().expect("the value of `-c` is not passed"));
|
||||
}
|
||||
"--check" => {
|
||||
cfg.mode = ErgMode::FullCheck;
|
||||
|
@ -630,15 +657,15 @@ USAGE:
|
|||
}
|
||||
}
|
||||
}
|
||||
if cfg.input == Input::REPL && cfg.mode != ErgMode::LanguageServer {
|
||||
if cfg.input.is_repl() && cfg.mode != ErgMode::LanguageServer {
|
||||
use crate::tty::IsTty;
|
||||
let is_stdin_piped = !stdin().is_tty();
|
||||
let input = if is_stdin_piped {
|
||||
let mut buffer = String::new();
|
||||
stdin().read_to_string(&mut buffer).unwrap();
|
||||
Input::Pipe(buffer)
|
||||
Input::pipe(buffer)
|
||||
} else {
|
||||
Input::REPL
|
||||
Input::repl()
|
||||
};
|
||||
cfg.input = input;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ pub mod opcode308;
|
|||
pub mod opcode310;
|
||||
pub mod opcode311;
|
||||
pub mod python_util;
|
||||
pub mod random;
|
||||
pub mod serialize;
|
||||
pub mod set;
|
||||
pub mod shared;
|
||||
|
|
7
crates/erg_common/random.rs
Normal file
7
crates/erg_common/random.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
use std::collections::hash_map::RandomState;
|
||||
use std::hash::{BuildHasher, Hasher};
|
||||
|
||||
pub fn random() -> u64 {
|
||||
let state = RandomState::new();
|
||||
state.build_hasher().finish()
|
||||
}
|
|
@ -577,8 +577,8 @@ pub trait Runnable: Sized + Default {
|
|||
let mut num_errors = 0;
|
||||
let mut instance = Self::new(cfg);
|
||||
let res = match instance.input() {
|
||||
Input::File(_) | Input::Pipe(_) | Input::Str(_) => instance.exec(),
|
||||
Input::REPL | Input::DummyREPL(_) => {
|
||||
Input::File(_) | Input::Pipe(_, _) | Input::Str(_, _) => instance.exec(),
|
||||
Input::REPL(_) | Input::DummyREPL(_) => {
|
||||
let output = stdout();
|
||||
let mut output = BufWriter::new(output.lock());
|
||||
if !quiet_repl {
|
||||
|
|
|
@ -83,7 +83,7 @@ impl Runnable for HIRBuilder {
|
|||
|
||||
impl Buildable for HIRBuilder {
|
||||
fn inherit(cfg: ErgConfig, shared: SharedCompilerResource) -> Self {
|
||||
let mod_name = Str::rc(cfg.input.file_stem());
|
||||
let mod_name = Str::rc(&cfg.input.file_stem());
|
||||
Self::new_with_cache(cfg, mod_name, shared)
|
||||
}
|
||||
fn build(&mut self, src: String, mode: &str) -> Result<CompleteArtifact, IncompleteArtifact> {
|
||||
|
|
|
@ -528,18 +528,18 @@ mod test {
|
|||
fn default_error_format_confirmation() {
|
||||
let mut errors = Vec::new();
|
||||
|
||||
let input = Input::Pipe("stack bug error".to_owned());
|
||||
let input = Input::pipe("stack bug error".to_owned());
|
||||
let loc = Location::Line(1);
|
||||
let err = CompileError::stack_bug(input, loc, 0, 0, "FileName");
|
||||
errors.push(err);
|
||||
|
||||
let input = Input::Pipe("checker bug error".to_owned());
|
||||
let input = Input::pipe("checker bug error".to_owned());
|
||||
let errno = 0;
|
||||
let err = TyCheckError::checker_bug(input, errno, Location::Unknown, "name", 1);
|
||||
errors.push(err);
|
||||
|
||||
let loc = Location::LineRange(1, 3);
|
||||
let input = Input::Pipe("args\nmissing\nerror".to_string());
|
||||
let input = Input::pipe("args\nmissing\nerror".to_string());
|
||||
let caused_by = "<caused_by>";
|
||||
let err = TyCheckError::args_missing_error(
|
||||
input,
|
||||
|
@ -559,7 +559,7 @@ mod test {
|
|||
};
|
||||
let expect = Type::Nat;
|
||||
let found = Type::Int;
|
||||
let input = Input::Pipe("return type error".to_string());
|
||||
let input = Input::pipe("return type error".to_string());
|
||||
let name = "name";
|
||||
let err = TyCheckError::return_type_error(
|
||||
input,
|
||||
|
@ -580,7 +580,7 @@ mod test {
|
|||
};
|
||||
let expect = Type::Nat;
|
||||
let found = Type::Int;
|
||||
let input = Input::Pipe("type mismatch error".to_string());
|
||||
let input = Input::pipe("type mismatch error".to_string());
|
||||
let err = TyCheckError::type_mismatch_error(
|
||||
input,
|
||||
errno,
|
||||
|
@ -595,7 +595,7 @@ mod test {
|
|||
);
|
||||
errors.push(err);
|
||||
|
||||
let input = Input::Pipe(
|
||||
let input = Input::pipe(
|
||||
"too_many_args_error(some_long_name_variable_1,
|
||||
some_long_name_variable_2,
|
||||
some_long_name_variable_3,
|
||||
|
@ -619,12 +619,12 @@ mod test {
|
|||
);
|
||||
errors.push(err);
|
||||
|
||||
let input = Input::Pipe("argument error".to_string());
|
||||
let input = Input::pipe("argument error".to_string());
|
||||
let loc = Location::range(1, 0, 1, 8);
|
||||
let err = TyCheckError::argument_error(input, errno, loc, caused_by.to_string(), 1, 2);
|
||||
errors.push(err);
|
||||
|
||||
let input = Input::Pipe("Nat <: Int <: Ratio".to_string());
|
||||
let input = Input::pipe("Nat <: Int <: Ratio".to_string());
|
||||
let loc = Location::range(1, 0, 1, 10);
|
||||
let sub_t = &Type::Nat;
|
||||
let sup_t = &Type::Int;
|
||||
|
@ -632,14 +632,14 @@ mod test {
|
|||
TyCheckError::subtyping_error(input, errno, sub_t, sup_t, loc, caused_by.to_string());
|
||||
errors.push(err);
|
||||
|
||||
let input = Input::Pipe("pred unification error".to_string());
|
||||
let input = Input::pipe("pred unification error".to_string());
|
||||
let lhs = &Predicate::Const("Str".into());
|
||||
let rhs = &Predicate::Const("Nat".into());
|
||||
let err =
|
||||
TyCheckError::pred_unification_error(input, errno, lhs, rhs, caused_by.to_string());
|
||||
errors.push(err);
|
||||
|
||||
let input = Input::Pipe("Trait member type error".to_string());
|
||||
let input = Input::pipe("Trait member type error".to_string());
|
||||
let errno = 0;
|
||||
let loc = Location::Range {
|
||||
ln_begin: 1,
|
||||
|
@ -663,7 +663,7 @@ mod test {
|
|||
);
|
||||
errors.push(err);
|
||||
|
||||
let input = Input::Pipe("trait member not defined error".to_string());
|
||||
let input = Input::pipe("trait member not defined error".to_string());
|
||||
let member_name = "member name";
|
||||
let trait_type = &Type::ClassType;
|
||||
let class_type = &Type::Ellipsis;
|
||||
|
@ -679,7 +679,7 @@ mod test {
|
|||
);
|
||||
errors.push(err);
|
||||
|
||||
let input = Input::Pipe("singular no attribute error".to_string());
|
||||
let input = Input::pipe("singular no attribute error".to_string());
|
||||
let loc = Location::Range {
|
||||
ln_begin: 1,
|
||||
col_begin: 0,
|
||||
|
@ -702,7 +702,7 @@ mod test {
|
|||
);
|
||||
errors.push(err);
|
||||
|
||||
let input = Input::Pipe("ambiguous type error".to_string());
|
||||
let input = Input::pipe("ambiguous type error".to_string());
|
||||
let expr = Identifier::new(
|
||||
Some(erg_parser::token::Token {
|
||||
kind: erg_parser::token::TokenKind::EOF,
|
||||
|
@ -728,7 +728,7 @@ mod test {
|
|||
EvalError::ambiguous_type_error(input, errno, &expr, candidates, caused_by.to_string());
|
||||
errors.push(err);
|
||||
|
||||
let input = Input::Pipe("invalid type cast error".to_string());
|
||||
let input = Input::pipe("invalid type cast error".to_string());
|
||||
let loc = Location::range(1, 8, 1, 17);
|
||||
let cast_to = Type::Error;
|
||||
let hint = Some("hint message here".to_string());
|
||||
|
@ -743,7 +743,7 @@ mod test {
|
|||
);
|
||||
errors.push(err);
|
||||
|
||||
let input = Input::Pipe("override error".to_string());
|
||||
let input = Input::pipe("override error".to_string());
|
||||
let name_loc = Location::range(1, 0, 1, 8);
|
||||
let superclass = &Type::Failure;
|
||||
let err = TyCheckError::override_error(
|
||||
|
@ -756,14 +756,14 @@ mod test {
|
|||
);
|
||||
errors.push(err);
|
||||
|
||||
let input = Input::Pipe("visibility error".to_string());
|
||||
let input = Input::pipe("visibility error".to_string());
|
||||
let loc = Location::Line(1);
|
||||
let vis = erg_common::vis::Visibility::Private;
|
||||
let err =
|
||||
TyCheckError::visibility_error(input, errno, loc, caused_by.to_string(), name, vis);
|
||||
errors.push(err);
|
||||
|
||||
let input = Input::Pipe("import nunpy as np".to_string());
|
||||
let input = Input::pipe("import nunpy as np".to_string());
|
||||
let errno = 0;
|
||||
let desc = "nunpy is not defined".to_string();
|
||||
let loc = Location::range(1, 7, 1, 12);
|
||||
|
|
|
@ -143,7 +143,8 @@ impl Runnable for Transpiler {
|
|||
}
|
||||
|
||||
fn exec(&mut self) -> Result<i32, Self::Errs> {
|
||||
let path = self.cfg.dump_path().replace(".er", ".py");
|
||||
let mut path = self.cfg.dump_path();
|
||||
path.set_extension(".py");
|
||||
let src = self.cfg.input.read();
|
||||
let artifact = self.transpile(src, "exec").map_err(|eart| {
|
||||
eart.warns.fmt_all_stderr();
|
||||
|
@ -181,7 +182,7 @@ impl ContextProvider for Transpiler {
|
|||
|
||||
impl Buildable<PyScript> for Transpiler {
|
||||
fn inherit(cfg: ErgConfig, shared: SharedCompilerResource) -> Self {
|
||||
let mod_name = Str::rc(cfg.input.file_stem());
|
||||
let mod_name = Str::from(cfg.input.file_stem());
|
||||
Self {
|
||||
shared: shared.clone(),
|
||||
builder: HIRBuilder::new_with_cache(cfg.copy(), mod_name, shared),
|
||||
|
|
|
@ -61,13 +61,15 @@ impl ASTBuilder {
|
|||
let module = self.runner.parse(src)?;
|
||||
let mut desugarer = Desugarer::new();
|
||||
let module = desugarer.desugar(module);
|
||||
let ast = AST::new(Str::rc(self.runner.cfg().input.full_path()), module);
|
||||
let path = self.runner.cfg().input.full_path();
|
||||
let ast = AST::new(Str::rc(path.to_str().unwrap()), module);
|
||||
Ok(ast)
|
||||
}
|
||||
|
||||
pub fn build_without_desugaring(&mut self, src: String) -> Result<AST, ParserRunnerErrors> {
|
||||
let module = self.runner.parse(src)?;
|
||||
let ast = AST::new(Str::rc(self.runner.cfg().input.full_path()), module);
|
||||
let path = self.runner.cfg().input.full_path();
|
||||
let ast = AST::new(Str::rc(path.to_str().unwrap()), module);
|
||||
Ok(ast)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -292,7 +292,7 @@ impl ParserRunner {
|
|||
}
|
||||
|
||||
pub fn parse(&mut self, src: String) -> Result<Module, ParserRunnerErrors> {
|
||||
let ts = Lexer::new(Input::Str(src))
|
||||
let ts = Lexer::new(Input::Str(self.cfg.input.id(), src))
|
||||
.lex()
|
||||
.map_err(|errs| ParserRunnerErrors::convert(self.input(), errs))?;
|
||||
Parser::new(ts)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue