diff --git a/compiler/erg_common/str.rs b/compiler/erg_common/str.rs index cde076e5..d92f9074 100644 --- a/compiler/erg_common/str.rs +++ b/compiler/erg_common/str.rs @@ -139,4 +139,55 @@ impl Str { .map(|c| c.is_uppercase()) .unwrap_or(false) } + + pub fn split_with(&self, seps: &[&str]) -> Vec<&str> { + let mut ret = vec![]; + let mut start = 0; + #[allow(unused_assignments)] + let mut end = 0; + let mut i = 0; + while i < self.len() { + let mut found = false; + for sep in seps { + if self[i..].starts_with(sep) { + end = i; + ret.push(&self[start..end]); + start = i + sep.len(); + i = start; + found = true; + break; + } + } + if !found { + i += 1; + } + } + ret.push(&self[start..]); + ret + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_split_with() { + assert_eq!( + Str::ever("aa::bb.cc").split_with(&[".", "::"]), + vec!["aa", "bb", "cc"] + ); + assert_eq!( + Str::ever("aa::bb.cc").split_with(&["::", "."]), + vec!["aa", "bb", "cc"] + ); + assert_eq!( + Str::ever("aaxxbbyycc").split_with(&["xx", "yy"]), + vec!["aa", "bb", "cc"] + ); + assert_ne!( + Str::ever("aaxxbbyycc").split_with(&["xx", "yy"]), + vec!["aa", "bb", "ff"] + ); + } } diff --git a/compiler/erg_compiler/context/inquire.rs b/compiler/erg_compiler/context/inquire.rs index 7a78be17..95368b75 100644 --- a/compiler/erg_compiler/context/inquire.rs +++ b/compiler/erg_compiler/context/inquire.rs @@ -1547,9 +1547,15 @@ impl Context { if let Some((_, ctx)) = self.rec_get_mono_type(&typ.local_name()) { return Some(ctx); } - let path = name.split("::").next().unwrap_or(name); - let path = path.split('.').next().unwrap_or(path); - let path = self.resolve_path(Path::new(path)); + // e.g. http.client.Response -> http.client + let mut namespaces = name.split_with(&[".", "::"]); + let type_name = namespaces.pop().unwrap(); // Response + let path = Path::new(namespaces.remove(0)); + let mut path = self.resolve_path(path); + for p in namespaces.into_iter() { + path = self.push_path(path, Path::new(p)); + } + log!("{}", path.display()); if let Some(ctx) = self .mod_cache .as_ref() @@ -1560,7 +1566,7 @@ impl Context { .and_then(|cache| cache.ref_ctx(path.as_path())) }) { - if let Some((_, ctx)) = ctx.rec_get_mono_type(&typ.local_name()) { + if let Some((_, ctx)) = ctx.rec_get_mono_type(type_name) { return Some(ctx); } } @@ -1570,9 +1576,13 @@ impl Context { return Some(ctx); } // NOTE: This needs to be changed if we want to be able to define classes/traits outside of the top level - let path = name.split("::").next().unwrap_or(name); - let path = path.split('.').next().unwrap_or(path); - let path = self.resolve_path(Path::new(path)); + let mut namespaces = name.split_with(&[".", "::"]); + let type_name = namespaces.pop().unwrap(); // Response + let path = Path::new(namespaces.remove(0)); + let mut path = self.resolve_path(path); + for p in namespaces.into_iter() { + path = self.push_path(path, Path::new(p)); + } if let Some(ctx) = self .mod_cache .as_ref() @@ -1583,7 +1593,7 @@ impl Context { .and_then(|cache| cache.ref_ctx(path.as_path())) }) { - if let Some((_, ctx)) = ctx.rec_get_poly_type(&typ.local_name()) { + if let Some((_, ctx)) = ctx.rec_get_poly_type(type_name) { return Some(ctx); } } @@ -1752,6 +1762,23 @@ impl Context { } } + pub(crate) fn push_path(&self, mut path: PathBuf, add: &Path) -> PathBuf { + path.pop(); // __init__.d.er + if let Ok(path) = path.join(add).canonicalize() { + path + } else if let Ok(path) = path.join(format!("{}.d.er", add.display())).canonicalize() { + path + } else if let Ok(path) = path + .join(format!("{}.d", add.display())) + .join("__init__.d.er") + .canonicalize() + { + path + } else { + todo!("{} {}", path.display(), add.display()) + } + } + // FIXME: 現在の実装だとimportしたモジュールはどこからでも見れる pub(crate) fn get_mod(&self, name: &str) -> Option<&Context> { let t = self.get_var_info(name).map(|(_, vi)| vi.t.clone()).ok()?; diff --git a/compiler/erg_compiler/context/instantiate.rs b/compiler/erg_compiler/context/instantiate.rs index 50c4dac9..5109fc42 100644 --- a/compiler/erg_compiler/context/instantiate.rs +++ b/compiler/erg_compiler/context/instantiate.rs @@ -824,7 +824,20 @@ impl Context { expr: &ast::ConstExpr, ) -> SingleTyCheckResult { match expr { - ast::ConstExpr::Accessor(ast::ConstAccessor::Local(name)) => Ok(mono(name.inspect())), + ast::ConstExpr::Accessor(ast::ConstAccessor::Local(name)) => { + if let Some((typ, _)) = self.rec_get_type(name.inspect()) { + Ok(typ.clone()) + } else { + Err(TyCheckError::no_var_error( + self.cfg.input.clone(), + line!() as usize, + name.loc(), + self.caused_by(), + name.inspect(), + self.get_similar_name(name.inspect()), + )) + } + } _ => todo!(), } } diff --git a/compiler/erg_compiler/context/register.rs b/compiler/erg_compiler/context/register.rs index 0fbd9e52..eeea6cfe 100644 --- a/compiler/erg_compiler/context/register.rs +++ b/compiler/erg_compiler/context/register.rs @@ -29,7 +29,6 @@ use crate::error::{ }; use crate::hir; use crate::hir::Literal; -use crate::mod_cache::SharedModuleCache; use crate::varinfo::{Mutability, ParamIdx, VarInfo, VarKind}; use Mutability::*; use RegistrationMode::*; @@ -1016,30 +1015,16 @@ impl Context { mod_name: &Literal, ) -> CompileResult { if kind.is_erg_import() { - self.import_erg_mod_using_cache(mod_name) + self.import_erg_mod(mod_name) } else { self.import_py_mod(mod_name) } } - fn import_erg_mod_using_cache(&mut self, mod_name: &Literal) -> CompileResult { + fn import_erg_mod(&self, mod_name: &Literal) -> CompileResult { let __name__ = enum_unwrap!(mod_name.value.clone(), ValueObj::Str); let mod_cache = self.mod_cache.as_ref().unwrap(); let py_mod_cache = self.py_mod_cache.as_ref().unwrap(); - #[allow(clippy::match_single_binding)] - match &__name__[..] { - // TODO: erg builtin modules - _ => self.import_erg_mod(__name__, mod_name, mod_cache, py_mod_cache), - } - } - - fn import_erg_mod( - &self, - __name__: Str, - mod_name: &Literal, - mod_cache: &SharedModuleCache, - py_mod_cache: &SharedModuleCache, - ) -> CompileResult { let path = match self.cfg.input.local_resolve(Path::new(&__name__[..])) { Ok(path) => path, Err(err) => { @@ -1097,6 +1082,27 @@ impl Context { path == pystd_path } + /// e.g. http.d/client.d.er -> http.client + /// math.d.er -> math + fn mod_name(&self, path: &Path) -> Str { + let mut name = path + .file_name() + .unwrap() + .to_str() + .unwrap() + .trim_end_matches(".d.er") + .to_string(); + for parent in path.components().rev().skip(1) { + let parent = parent.as_os_str().to_str().unwrap(); + if parent.ends_with(".d") { + name = parent.trim_end_matches(".d").to_string() + "." + &name; + } else { + break; + } + } + Str::from(name) + } + fn import_py_mod(&self, mod_name: &Literal) -> CompileResult { let __name__ = enum_unwrap!(mod_name.value.clone(), ValueObj::Str); let mod_cache = self.mod_cache.as_ref().unwrap(); @@ -1137,8 +1143,12 @@ impl Context { } let cfg = ErgConfig::with_module_path(path.clone()); let src = cfg.input.read(); - let mut builder = - HIRBuilder::new_with_cache(cfg, __name__, mod_cache.clone(), py_mod_cache.clone()); + let mut builder = HIRBuilder::new_with_cache( + cfg, + self.mod_name(&path), + mod_cache.clone(), + py_mod_cache.clone(), + ); match builder.build(src, "declare") { Ok(hir) => { let ctx = builder.pop_mod_ctx(); diff --git a/compiler/erg_compiler/context/tyvar.rs b/compiler/erg_compiler/context/tyvar.rs index 8d6b3962..929364b3 100644 --- a/compiler/erg_compiler/context/tyvar.rs +++ b/compiler/erg_compiler/context/tyvar.rs @@ -795,8 +795,8 @@ impl Context { for attr in record.attrs.iter_mut() { match &mut attr.sig { hir::Signature::Var(var) => { - var.t = - self.deref_tyvar(mem::take(&mut var.t), Covariant, var.loc())?; + *var.ref_mut_t() = + self.deref_tyvar(mem::take(var.ref_mut_t()), Covariant, var.loc())?; } hir::Signature::Subr(subr) => { subr.t = @@ -851,8 +851,8 @@ impl Context { if !def.sig.ref_t().is_quantified() { match &mut def.sig { hir::Signature::Var(var) => { - var.t = - self.deref_tyvar(mem::take(&mut var.t), Covariant, var.loc())?; + *var.ref_mut_t() = + self.deref_tyvar(mem::take(var.ref_mut_t()), Covariant, var.loc())?; } hir::Signature::Subr(subr) => { subr.t = diff --git a/compiler/erg_compiler/hir.rs b/compiler/erg_compiler/hir.rs index c9658c07..601d2f4d 100644 --- a/compiler/erg_compiler/hir.rs +++ b/compiler/erg_compiler/hir.rs @@ -548,8 +548,8 @@ impl Accessor { pub fn local_name(&self) -> Option<&str> { match self { Self::Ident(ident) => ident.qual_name.as_ref().map(|s| { - let name = s.split("::").last().unwrap_or(&s[..]); - name.split('.').last().unwrap_or(name) + let mut seps = s.split_with(&[".", "::"]); + seps.remove(seps.len() - 1) }), _ => None, } @@ -1200,22 +1200,39 @@ impl Locational for Block { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct VarSignature { pub ident: Identifier, - pub t: Type, } impl NestedDisplay for VarSignature { fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result { - write!(f, "{}(: {})", self.ident, self.t) + write!(f, "{}", self.ident) } } impl_display_from_nested!(VarSignature); impl_locational!(VarSignature, ident); -impl_t!(VarSignature); + +impl HasType for VarSignature { + #[inline] + fn ref_t(&self) -> &Type { + self.ident.ref_t() + } + #[inline] + fn ref_mut_t(&mut self) -> &mut Type { + self.ident.ref_mut_t() + } + #[inline] + fn signature_t(&self) -> Option<&Type> { + self.ident.signature_t() + } + #[inline] + fn signature_mut_t(&mut self) -> Option<&mut Type> { + self.ident.signature_mut_t() + } +} impl VarSignature { - pub const fn new(ident: Identifier, t: Type) -> Self { - Self { ident, t } + pub const fn new(ident: Identifier) -> Self { + Self { ident } } pub fn inspect(&self) -> &Str { diff --git a/compiler/erg_compiler/lib/pystd/http.d/__init__.d.er b/compiler/erg_compiler/lib/pystd/http.d/__init__.d.er index c49b8e62..5375fa93 100644 --- a/compiler/erg_compiler/lib/pystd/http.d/__init__.d.er +++ b/compiler/erg_compiler/lib/pystd/http.d/__init__.d.er @@ -1 +1 @@ -.client = pyimport "./client" +.client = pyimport "client" diff --git a/compiler/erg_compiler/lib/pystd/http.d/client.d.er b/compiler/erg_compiler/lib/pystd/http.d/client.d.er index d19fcaf2..33642f33 100644 --- a/compiler/erg_compiler/lib/pystd/http.d/client.d.er +++ b/compiler/erg_compiler/lib/pystd/http.d/client.d.er @@ -1 +1,3 @@ .HTTPResponse: ClassType +.HTTPResponse <: FileLike +.HTTPResponse <: FileLike! diff --git a/compiler/erg_compiler/lib/pystd/urllib.d/__init__.d.er b/compiler/erg_compiler/lib/pystd/urllib.d/__init__.d.er index 5ed7890b..127a9678 100644 --- a/compiler/erg_compiler/lib/pystd/urllib.d/__init__.d.er +++ b/compiler/erg_compiler/lib/pystd/urllib.d/__init__.d.er @@ -1,2 +1,2 @@ -.parse = pyimport "./parse" -.request = pyimport "./request" +.parse = pyimport "parse" +.request = pyimport "request" diff --git a/compiler/erg_compiler/link.rs b/compiler/erg_compiler/link.rs index 4b7ced63..09067e14 100644 --- a/compiler/erg_compiler/link.rs +++ b/compiler/erg_compiler/link.rs @@ -13,7 +13,7 @@ use erg_parser::token::{Token, TokenKind}; use crate::ty::free::fresh_varname; use crate::ty::typaram::TyParam; use crate::ty::value::ValueObj; -use crate::ty::{HasType, Type}; +use crate::ty::HasType; use crate::hir::*; use crate::mod_cache::SharedModuleCache; @@ -312,7 +312,7 @@ impl<'a> Linker<'a> { let tmp = Identifier::private_with_line(Str::from(fresh_varname()), expr.ln_begin().unwrap()); let mod_def = Expr::Def(Def::new( - Signature::Var(VarSignature::new(tmp.clone(), Type::Uninited)), + Signature::Var(VarSignature::new(tmp.clone())), DefBody::new(Token::dummy(), block, DefId(0)), )); let module = Expr::Accessor(Accessor::Ident(tmp)); diff --git a/compiler/erg_compiler/lower.rs b/compiler/erg_compiler/lower.rs index 5b7c1787..0e3b3c1f 100644 --- a/compiler/erg_compiler/lower.rs +++ b/compiler/erg_compiler/lower.rs @@ -932,8 +932,9 @@ impl ASTLowerer { body.id, None, )?; - let ident = hir::Identifier::bare(ident.dot.clone(), ident.name.clone()); - let sig = hir::VarSignature::new(ident, found_body_t.clone()); + let mut ident = hir::Identifier::bare(ident.dot.clone(), ident.name.clone()); + ident.vi.t = found_body_t.clone(); + let sig = hir::VarSignature::new(ident); let body = hir::DefBody::new(body.op, block, body.id); Ok(hir::Def::new(hir::Signature::Var(sig), body)) } @@ -1515,8 +1516,9 @@ impl ASTLowerer { }; let id = body.id; self.ctx.assign_var_sig(&sig, found_body_t, id, py_name)?; - let ident = hir::Identifier::bare(ident.dot.clone(), ident.name.clone()); - let sig = hir::VarSignature::new(ident, found_body_t.clone()); + let mut ident = hir::Identifier::bare(ident.dot.clone(), ident.name.clone()); + ident.vi.t = found_body_t.clone(); + let sig = hir::VarSignature::new(ident); let body = hir::DefBody::new(body.op, block, body.id); Ok(hir::Def::new(hir::Signature::Var(sig), body)) } diff --git a/compiler/erg_compiler/ty/mod.rs b/compiler/erg_compiler/ty/mod.rs index a83ea720..8256b6d5 100644 --- a/compiler/erg_compiler/ty/mod.rs +++ b/compiler/erg_compiler/ty/mod.rs @@ -1955,9 +1955,8 @@ impl Type { pub fn local_name(&self) -> Str { match self { Self::Mono(name) | Self::Poly { name, .. } => { - let name = name.split("::").last().unwrap_or(name); - let name = name.split('.').last().unwrap_or(name); - Str::rc(name) + let namespaces = name.split_with(&[".", "::"]); + Str::rc(namespaces.last().unwrap()) } _ => self.qual_name(), }