Merge pull request #371 from erg-lang/fix-370

Fix #370
This commit is contained in:
Shunsuke Shibayama 2023-01-28 12:59:56 +09:00 committed by GitHub
commit 493492d0db
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 110 additions and 72 deletions

View file

@ -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;
}

View file

@ -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;

View 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()
}

View file

@ -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 {

View file

@ -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> {

View file

@ -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);

View file

@ -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),

View file

@ -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)
}
}

View file

@ -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)