feat: add special namespaces module/global

This commit is contained in:
Shunsuke Shibayama 2023-05-03 14:32:09 +09:00
parent c4a0efae08
commit 730886021e
29 changed files with 349 additions and 193 deletions

View file

@ -1,3 +1,4 @@
use erg_common::consts::PYTHON_MODE;
use lsp_types::CompletionResponse; use lsp_types::CompletionResponse;
use serde_json::Value; use serde_json::Value;
@ -183,7 +184,7 @@ fn external_item(name: &str, vi: &VarInfo, mod_name: &str) -> CompletionItem {
CompletionItem::new_simple(format!("{name} (import from {mod_name})"), vi.t.to_string()); CompletionItem::new_simple(format!("{name} (import from {mod_name})"), vi.t.to_string());
item.sort_text = Some(format!("{}_{}", CompletionOrder::STD_ITEM, item.label)); item.sort_text = Some(format!("{}_{}", CompletionOrder::STD_ITEM, item.label));
item.kind = Some(comp_item_kind(vi)); item.kind = Some(comp_item_kind(vi));
let import = if cfg!(feature = "py_compat") { let import = if PYTHON_MODE {
format!("from {mod_name} import {name}\n") format!("from {mod_name} import {name}\n")
} else { } else {
format!("{{{name};}} = pyimport \"{mod_name}\"\n") format!("{{{name};}} = pyimport \"{mod_name}\"\n")
@ -226,7 +227,7 @@ fn module_completions() -> Vec<CompletionItem> {
); );
item.sort_text = Some(format!("{}_{}", CompletionOrder::STD_ITEM, item.label)); item.sort_text = Some(format!("{}_{}", CompletionOrder::STD_ITEM, item.label));
item.kind = Some(CompletionItemKind::MODULE); item.kind = Some(CompletionItemKind::MODULE);
let import = if cfg!(feature = "py_compat") { let import = if PYTHON_MODE {
format!("import {mod_name}\n") format!("import {mod_name}\n")
} else { } else {
format!("{mod_name} = pyimport \"{mod_name}\"\n") format!("{mod_name} = pyimport \"{mod_name}\"\n")

View file

@ -1,3 +1,4 @@
use erg_common::consts::PYTHON_MODE;
use erg_common::traits::{Locational, Stream}; use erg_common::traits::{Locational, Stream};
use erg_compiler::artifact::BuildRunnable; use erg_compiler::artifact::BuildRunnable;
use erg_compiler::context::register::PylyzerStatus; use erg_compiler::context::register::PylyzerStatus;
@ -86,7 +87,7 @@ impl<Checker: BuildRunnable> Server<Checker> {
match (&vi.def_loc.module, util::loc_to_range(vi.def_loc.loc)) { match (&vi.def_loc.module, util::loc_to_range(vi.def_loc.loc)) {
(Some(path), Some(range)) => { (Some(path), Some(range)) => {
let def_uri = NormalizedUrl::try_from(path.as_path()).unwrap(); let def_uri = NormalizedUrl::try_from(path.as_path()).unwrap();
let def_file = if cfg!(feature = "py_compat") { let def_file = if PYTHON_MODE {
let header = self let header = self
.file_cache .file_cache
.get_line(&def_uri, 0) .get_line(&def_uri, 0)

View file

@ -1,3 +1,4 @@
use erg_common::consts::ERG_MODE;
use erg_common::traits::Locational; use erg_common::traits::Locational;
use erg_common::Str; use erg_common::Str;
use erg_compiler::erg_parser::token::Token; use erg_compiler::erg_parser::token::Token;
@ -25,7 +26,7 @@ impl<'a> HIRVisitor<'a> {
hir, hir,
file_cache, file_cache,
uri, uri,
strict_cmp: !cfg!(feature = "py_compat"), strict_cmp: ERG_MODE,
} }
} }

View file

@ -1,3 +1,4 @@
use erg_common::consts::PYTHON_MODE;
use erg_common::lang::LanguageCode; use erg_common::lang::LanguageCode;
use erg_common::trim_eliminate_top_indent; use erg_common::trim_eliminate_top_indent;
use erg_compiler::artifact::BuildRunnable; use erg_compiler::artifact::BuildRunnable;
@ -10,11 +11,7 @@ use lsp_types::{Hover, HoverContents, HoverParams, MarkedString, Url};
use crate::server::{send_log, ELSResult, Server}; use crate::server::{send_log, ELSResult, Server};
use crate::util::{self, NormalizedUrl}; use crate::util::{self, NormalizedUrl};
const PROG_LANG: &str = if cfg!(feature = "py_compat") { const PROG_LANG: &str = if PYTHON_MODE { "python" } else { "erg" };
"python"
} else {
"erg"
};
const ERG_LANG: &str = "erg"; const ERG_LANG: &str = "erg";
@ -223,7 +220,9 @@ impl<Checker: BuildRunnable> Server<Checker> {
} }
}; };
def_pos.line = def_pos.line.saturating_sub(1); def_pos.line = def_pos.line.saturating_sub(1);
let def_uri = NormalizedUrl::new(Url::from_file_path(module).unwrap()); let Ok(def_uri) = NormalizedUrl::try_from(module.as_path()) else {
return Ok(());
};
let mut default_code_block = "".to_string(); let mut default_code_block = "".to_string();
let Some(stream) = self.file_cache.get_token_stream(&def_uri) else { let Some(stream) = self.file_cache.get_token_stream(&def_uri) else {
return Ok(()); return Ok(());

View file

@ -130,7 +130,7 @@ impl ASTSemanticState {
fn gen_from_poly_typespec(&mut self, t_spec: PolyTypeSpec) -> Vec<SemanticToken> { fn gen_from_poly_typespec(&mut self, t_spec: PolyTypeSpec) -> Vec<SemanticToken> {
let mut tokens = vec![]; let mut tokens = vec![];
let token = self.gen_token(t_spec.ident.name.loc(), SemanticTokenType::TYPE); let token = self.gen_token(t_spec.acc.loc(), SemanticTokenType::TYPE);
tokens.push(token); tokens.push(token);
tokens tokens
} }

View file

@ -5,6 +5,7 @@ use std::ops::Not;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::str::FromStr; use std::str::FromStr;
use erg_common::consts::PYTHON_MODE;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::json; use serde_json::json;
use serde_json::Value; use serde_json::Value;
@ -227,7 +228,7 @@ impl<Checker: BuildRunnable> Server<Checker> {
} }
pub const fn mode(&self) -> &str { pub const fn mode(&self) -> &str {
if cfg!(feature = "py_compat") { if PYTHON_MODE {
"pylyzer" "pylyzer"
} else { } else {
"erg" "erg"

View file

@ -1,3 +1,8 @@
pub const SEMVER: &str = env!("CARGO_PKG_VERSION"); pub const SEMVER: &str = env!("CARGO_PKG_VERSION");
pub const GIT_HASH_SHORT: &str = env!("GIT_HASH_SHORT"); pub const GIT_HASH_SHORT: &str = env!("GIT_HASH_SHORT");
pub const BUILD_DATE: &str = env!("BUILD_DATE"); pub const BUILD_DATE: &str = env!("BUILD_DATE");
pub const PYTHON_MODE: bool = cfg!(feature = "py_compat");
pub const ERG_MODE: bool = !cfg!(feature = "py_compat");
pub const ELS: bool = cfg!(feature = "els");
pub const DEBUG_MODE: bool = cfg!(feature = "debug");

View file

@ -1,5 +1,7 @@
use std::str::FromStr; use std::str::FromStr;
use crate::consts::{ERG_MODE, PYTHON_MODE};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum LanguageCode { pub enum LanguageCode {
English, English,
@ -107,8 +109,8 @@ impl LanguageCode {
Self::Japanese => cfg!(feature = "japanese"), Self::Japanese => cfg!(feature = "japanese"),
Self::SimplifiedChinese => cfg!(feature = "simplified_chinese"), Self::SimplifiedChinese => cfg!(feature = "simplified_chinese"),
Self::TraditionalChinese => cfg!(feature = "traditional_chinese"), Self::TraditionalChinese => cfg!(feature = "traditional_chinese"),
Self::Erg => !cfg!(feature = "py_compat"), Self::Erg => ERG_MODE,
Self::Python => cfg!(feature = "py_compat"), Self::Python => PYTHON_MODE,
Self::ErgOrPython => true, Self::ErgOrPython => true,
} }
} }

View file

@ -1372,7 +1372,8 @@ impl Context {
t.clone() t.clone()
} else { } else {
let tv = Type::FreeVar(new_fv); let tv = Type::FreeVar(new_fv);
tv_cache.push_or_init_tyvar(&name, &tv, self); let varname = VarName::from_str(name.clone());
tv_cache.push_or_init_tyvar(&varname, &tv, self);
tv tv
} }
} }
@ -1397,7 +1398,8 @@ impl Context {
tp.clone() tp.clone()
} else { } else {
let tp = TyParam::FreeVar(new_fv); let tp = TyParam::FreeVar(new_fv);
tv_cache.push_or_init_typaram(&name, &tp, self); let varname = VarName::from_str(name.clone());
tv_cache.push_or_init_typaram(&varname, &tp, self);
tp tp
} }
} }

View file

@ -1,3 +1,4 @@
use erg_common::consts::{ERG_MODE, PYTHON_MODE};
#[allow(unused_imports)] #[allow(unused_imports)]
use erg_common::log; use erg_common::log;
use erg_common::Str as StrStruct; use erg_common::Str as StrStruct;
@ -16,7 +17,7 @@ use Mutability::*;
impl Context { impl Context {
pub(super) fn init_builtin_classes(&mut self) { pub(super) fn init_builtin_classes(&mut self) {
let vis = if cfg!(feature = "py_compat") { let vis = if PYTHON_MODE {
Visibility::BUILTIN_PUBLIC Visibility::BUILTIN_PUBLIC
} else { } else {
Visibility::BUILTIN_PRIVATE Visibility::BUILTIN_PRIVATE
@ -1155,7 +1156,7 @@ impl Context {
let mut module = Self::builtin_poly_class(MODULE, vec![PS::named_nd(PATH, Str)], 2); let mut module = Self::builtin_poly_class(MODULE, vec![PS::named_nd(PATH, Str)], 2);
module.register_superclass(g_module_t.clone(), &generic_module); module.register_superclass(g_module_t.clone(), &generic_module);
let mut py_module = Self::builtin_poly_class(PY_MODULE, vec![PS::named_nd(PATH, Str)], 2); let mut py_module = Self::builtin_poly_class(PY_MODULE, vec![PS::named_nd(PATH, Str)], 2);
if !cfg!(feature = "py_compat") { if ERG_MODE {
py_module.register_superclass(g_module_t.clone(), &generic_module); py_module.register_superclass(g_module_t.clone(), &generic_module);
} }
/* GenericArray */ /* GenericArray */
@ -2178,32 +2179,16 @@ impl Context {
self.register_builtin_type(Never, never, vis.clone(), Const, Some(NEVER)); self.register_builtin_type(Never, never, vis.clone(), Const, Some(NEVER));
self.register_builtin_type(Obj, obj, vis.clone(), Const, Some(FUNC_OBJECT)); self.register_builtin_type(Obj, obj, vis.clone(), Const, Some(FUNC_OBJECT));
// self.register_type(mono(RECORD), vec![], record, Visibility::BUILTIN_PRIVATE, Const); // self.register_type(mono(RECORD), vec![], record, Visibility::BUILTIN_PRIVATE, Const);
let name = if cfg!(feature = "py_compat") { let name = if PYTHON_MODE { FUNC_INT } else { INT };
FUNC_INT
} else {
INT
};
self.register_builtin_type(Int, int, vis.clone(), Const, Some(name)); self.register_builtin_type(Int, int, vis.clone(), Const, Some(name));
self.register_builtin_type(Nat, nat, vis.clone(), Const, Some(NAT)); self.register_builtin_type(Nat, nat, vis.clone(), Const, Some(NAT));
let name = if cfg!(feature = "py_compat") { let name = if PYTHON_MODE { FUNC_FLOAT } else { FLOAT };
FUNC_FLOAT
} else {
FLOAT
};
self.register_builtin_type(Complex, complex, vis.clone(), Const, Some(COMPLEX)); self.register_builtin_type(Complex, complex, vis.clone(), Const, Some(COMPLEX));
self.register_builtin_type(Float, float, vis.clone(), Const, Some(name)); self.register_builtin_type(Float, float, vis.clone(), Const, Some(name));
self.register_builtin_type(Ratio, ratio, vis.clone(), Const, Some(RATIO)); self.register_builtin_type(Ratio, ratio, vis.clone(), Const, Some(RATIO));
let name = if cfg!(feature = "py_compat") { let name = if PYTHON_MODE { FUNC_BOOL } else { BOOL };
FUNC_BOOL
} else {
BOOL
};
self.register_builtin_type(Bool, bool_, vis.clone(), Const, Some(name)); self.register_builtin_type(Bool, bool_, vis.clone(), Const, Some(name));
let name = if cfg!(feature = "py_compat") { let name = if PYTHON_MODE { FUNC_STR } else { STR };
FUNC_STR
} else {
STR
};
self.register_builtin_type(Str, str_, vis.clone(), Const, Some(name)); self.register_builtin_type(Str, str_, vis.clone(), Const, Some(name));
self.register_builtin_type(NoneType, nonetype, vis.clone(), Const, Some(NONE_TYPE)); self.register_builtin_type(NoneType, nonetype, vis.clone(), Const, Some(NONE_TYPE));
self.register_builtin_type(Type, type_, vis.clone(), Const, Some(FUNC_TYPE)); self.register_builtin_type(Type, type_, vis.clone(), Const, Some(FUNC_TYPE));
@ -2365,7 +2350,7 @@ impl Context {
self.register_builtin_type(mono(PROC), proc, vis.clone(), Const, Some(PROC)); self.register_builtin_type(mono(PROC), proc, vis.clone(), Const, Some(PROC));
self.register_builtin_type(mono(FUNC), func, vis.clone(), Const, Some(FUNC)); self.register_builtin_type(mono(FUNC), func, vis.clone(), Const, Some(FUNC));
self.register_builtin_type(range_t, range, vis.clone(), Const, Some(FUNC_RANGE)); self.register_builtin_type(range_t, range, vis.clone(), Const, Some(FUNC_RANGE));
if !cfg!(feature = "py_compat") { if ERG_MODE {
self.register_builtin_type(module_t, module, vis.clone(), Const, Some(MODULE_TYPE)); self.register_builtin_type(module_t, module, vis.clone(), Const, Some(MODULE_TYPE));
self.register_builtin_type( self.register_builtin_type(
mono(MUTABLE_OBJ), mono(MUTABLE_OBJ),

View file

@ -1,3 +1,4 @@
use erg_common::consts::{DEBUG_MODE, ERG_MODE, PYTHON_MODE};
#[allow(unused_imports)] #[allow(unused_imports)]
use erg_common::log; use erg_common::log;
@ -14,7 +15,7 @@ use Mutability::*;
impl Context { impl Context {
pub(super) fn init_builtin_funcs(&mut self) { pub(super) fn init_builtin_funcs(&mut self) {
let vis = if cfg!(feature = "py_compat") { let vis = if PYTHON_MODE {
Visibility::BUILTIN_PUBLIC Visibility::BUILTIN_PUBLIC
} else { } else {
Visibility::BUILTIN_PRIVATE Visibility::BUILTIN_PRIVATE
@ -347,13 +348,9 @@ impl Context {
self.register_builtin_py_impl(FUNC_STR, t_str, Immutable, vis.clone(), Some(FUNC_STR__)); self.register_builtin_py_impl(FUNC_STR, t_str, Immutable, vis.clone(), Some(FUNC_STR__));
self.register_builtin_py_impl(FUNC_SUM, t_sum, Immutable, vis.clone(), Some(FUNC_SUM)); self.register_builtin_py_impl(FUNC_SUM, t_sum, Immutable, vis.clone(), Some(FUNC_SUM));
self.register_builtin_py_impl(FUNC_ZIP, t_zip, Immutable, vis.clone(), Some(FUNC_ZIP)); self.register_builtin_py_impl(FUNC_ZIP, t_zip, Immutable, vis.clone(), Some(FUNC_ZIP));
let name = if cfg!(feature = "py_compat") { let name = if PYTHON_MODE { FUNC_INT } else { FUNC_INT__ };
FUNC_INT
} else {
FUNC_INT__
};
self.register_builtin_py_impl(FUNC_INT, t_int, Immutable, vis.clone(), Some(name)); self.register_builtin_py_impl(FUNC_INT, t_int, Immutable, vis.clone(), Some(name));
if cfg!(feature = "debug") { if DEBUG_MODE {
self.register_builtin_py_impl( self.register_builtin_py_impl(
PY, PY,
t_pyimport.clone(), t_pyimport.clone(),
@ -362,7 +359,7 @@ impl Context {
Some(FUNDAMENTAL_IMPORT), Some(FUNDAMENTAL_IMPORT),
); );
} }
if !cfg!(feature = "py_compat") { if ERG_MODE {
self.register_builtin_py_impl(FUNC_IF, t_if, Immutable, vis.clone(), Some(FUNC_IF__)); self.register_builtin_py_impl(FUNC_IF, t_if, Immutable, vis.clone(), Some(FUNC_IF__));
self.register_builtin_py_impl( self.register_builtin_py_impl(
FUNC_DISCARD, FUNC_DISCARD,
@ -467,7 +464,7 @@ impl Context {
} }
pub(super) fn init_builtin_const_funcs(&mut self) { pub(super) fn init_builtin_const_funcs(&mut self) {
let vis = if cfg!(feature = "py_compat") { let vis = if PYTHON_MODE {
Visibility::BUILTIN_PUBLIC Visibility::BUILTIN_PUBLIC
} else { } else {
Visibility::BUILTIN_PRIVATE Visibility::BUILTIN_PRIVATE

View file

@ -13,6 +13,7 @@ mod traits;
use std::path::PathBuf; use std::path::PathBuf;
use erg_common::config::ErgConfig; use erg_common::config::ErgConfig;
use erg_common::consts::{DEBUG_MODE, ERG_MODE, PYTHON_MODE};
use erg_common::dict; use erg_common::dict;
use erg_common::error::Location; use erg_common::error::Location;
use erg_common::fresh::fresh_varname; use erg_common::fresh::fresh_varname;
@ -501,7 +502,7 @@ impl Context {
vis: Visibility, vis: Visibility,
py_name: Option<&'static str>, py_name: Option<&'static str>,
) { ) {
if cfg!(feature = "debug") { if DEBUG_MODE {
if let Type::Subr(subr) = &t { if let Type::Subr(subr) = &t {
if subr.has_qvar() { if subr.has_qvar() {
panic!("not quantified subr: {subr}"); panic!("not quantified subr: {subr}");
@ -513,7 +514,7 @@ impl Context {
} else { } else {
None None
}; };
let name = if cfg!(feature = "py_compat") { let name = if PYTHON_MODE {
if let Some(py_name) = py_name { if let Some(py_name) = py_name {
VarName::from_static(py_name) VarName::from_static(py_name)
} else { } else {
@ -603,7 +604,7 @@ impl Context {
vis: Visibility, vis: Visibility,
py_name: Option<&'static str>, py_name: Option<&'static str>,
) { ) {
let name = if cfg!(feature = "py_compat") { let name = if PYTHON_MODE {
if let Some(py_name) = py_name { if let Some(py_name) = py_name {
VarName::from_static(py_name) VarName::from_static(py_name)
} else { } else {
@ -622,7 +623,7 @@ impl Context {
py_name: Option<&'static str>, py_name: Option<&'static str>,
lineno: u32, lineno: u32,
) { ) {
let name = if cfg!(feature = "py_compat") { let name = if PYTHON_MODE {
if let Some(py_name) = py_name { if let Some(py_name) = py_name {
VarName::from_static(py_name) VarName::from_static(py_name)
} else { } else {
@ -631,7 +632,7 @@ impl Context {
} else { } else {
VarName::from_static(name) VarName::from_static(name)
}; };
let vis = if cfg!(feature = "py_compat") || &self.name[..] != "<builtins>" { let vis = if PYTHON_MODE || &self.name[..] != "<builtins>" {
Visibility::BUILTIN_PUBLIC Visibility::BUILTIN_PUBLIC
} else { } else {
Visibility::BUILTIN_PRIVATE Visibility::BUILTIN_PRIVATE
@ -804,7 +805,7 @@ impl Context {
.map(|tp| ParamTy::Pos(tp_enum(self.get_tp_t(&tp).unwrap_or(Obj), set! { tp }))) .map(|tp| ParamTy::Pos(tp_enum(self.get_tp_t(&tp).unwrap_or(Obj), set! { tp })))
.collect(); .collect();
let meta_t = func(params, None, vec![], v_enum(set! { val.clone() })).quantify(); let meta_t = func(params, None, vec![], v_enum(set! { val.clone() })).quantify();
if !cfg!(feature = "py_compat") { if ERG_MODE {
self.locals.insert( self.locals.insert(
name.clone(), name.clone(),
VarInfo::new( VarInfo::new(
@ -897,7 +898,7 @@ impl Context {
} }
fn init_builtin_consts(&mut self) { fn init_builtin_consts(&mut self) {
let vis = if cfg!(feature = "py_compat") { let vis = if PYTHON_MODE {
Visibility::BUILTIN_PUBLIC Visibility::BUILTIN_PUBLIC
} else { } else {
Visibility::BUILTIN_PRIVATE Visibility::BUILTIN_PRIVATE
@ -956,7 +957,7 @@ impl Context {
ctx.init_builtin_funcs(); ctx.init_builtin_funcs();
ctx.init_builtin_const_funcs(); ctx.init_builtin_const_funcs();
ctx.init_builtin_procs(); ctx.init_builtin_procs();
if cfg!(feature = "py_compat") { if PYTHON_MODE {
ctx.init_py_compat_builtin_operators(); ctx.init_py_compat_builtin_operators();
} else { } else {
ctx.init_builtin_operators(); ctx.init_builtin_operators();

View file

@ -13,7 +13,7 @@ use Mutability::*;
impl Context { impl Context {
pub(super) fn init_builtin_procs(&mut self) { pub(super) fn init_builtin_procs(&mut self) {
let vis = if cfg!(feature = "py_compat") { let vis = if PYTHON_MODE {
Visibility::BUILTIN_PUBLIC Visibility::BUILTIN_PUBLIC
} else { } else {
Visibility::BUILTIN_PRIVATE Visibility::BUILTIN_PRIVATE
@ -73,7 +73,7 @@ impl Context {
T.clone(), T.clone(),
) )
.quantify(); .quantify();
let t_cond = if cfg!(feature = "py_compat") { let t_cond = if PYTHON_MODE {
Bool Bool
} else { } else {
// not Bool! type because `cond` may be the result of evaluation of a mutable object's method returns Bool. // not Bool! type because `cond` may be the result of evaluation of a mutable object's method returns Bool.
@ -103,7 +103,7 @@ impl Context {
mono("File!"), mono("File!"),
) )
.quantify(); .quantify();
let C = if cfg!(feature = "py_compat") { let C = if PYTHON_MODE {
mono("ContextManager").structuralize() mono("ContextManager").structuralize()
} else { } else {
mono("ContextManager") mono("ContextManager")
@ -131,29 +131,13 @@ impl Context {
self.register_builtin_py_impl("locals!", t_locals, Immutable, vis.clone(), Some("locals")); self.register_builtin_py_impl("locals!", t_locals, Immutable, vis.clone(), Some("locals"));
self.register_builtin_py_impl("next!", t_next, Immutable, vis.clone(), Some("next")); self.register_builtin_py_impl("next!", t_next, Immutable, vis.clone(), Some("next"));
self.register_py_builtin("open!", t_open, Some("open"), 198); self.register_py_builtin("open!", t_open, Some("open"), 198);
let name = if cfg!(feature = "py_compat") { let name = if PYTHON_MODE { "if" } else { "if__" };
"if"
} else {
"if__"
};
self.register_builtin_py_impl("if!", t_if, Immutable, vis.clone(), Some(name)); self.register_builtin_py_impl("if!", t_if, Immutable, vis.clone(), Some(name));
let name = if cfg!(feature = "py_compat") { let name = if PYTHON_MODE { "for" } else { "for__" };
"for"
} else {
"for__"
};
self.register_builtin_py_impl("for!", t_for, Immutable, vis.clone(), Some(name)); self.register_builtin_py_impl("for!", t_for, Immutable, vis.clone(), Some(name));
let name = if cfg!(feature = "py_compat") { let name = if PYTHON_MODE { "while" } else { "while__" };
"while"
} else {
"while__"
};
self.register_builtin_py_impl("while!", t_while, Immutable, vis.clone(), Some(name)); self.register_builtin_py_impl("while!", t_while, Immutable, vis.clone(), Some(name));
let name = if cfg!(feature = "py_compat") { let name = if PYTHON_MODE { "with" } else { "with__" };
"with"
} else {
"with__"
};
self.register_builtin_py_impl("with!", t_with, Immutable, vis, Some(name)); self.register_builtin_py_impl("with!", t_with, Immutable, vis, Some(name));
} }
} }

View file

@ -21,7 +21,7 @@ impl Context {
// 型境界はすべて各サブルーチンで定義する // 型境界はすべて各サブルーチンで定義する
// push_subtype_boundなどはユーザー定義APIの型境界決定のために使用する // push_subtype_boundなどはユーザー定義APIの型境界決定のために使用する
pub(super) fn init_builtin_traits(&mut self) { pub(super) fn init_builtin_traits(&mut self) {
let vis = if cfg!(feature = "py_compat") { let vis = if PYTHON_MODE {
Visibility::BUILTIN_PUBLIC Visibility::BUILTIN_PUBLIC
} else { } else {
Visibility::BUILTIN_PRIVATE Visibility::BUILTIN_PRIVATE

View file

@ -3,6 +3,7 @@ use std::option::Option; // conflicting to Type::Option
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use erg_common::config::{ErgConfig, Input}; use erg_common::config::{ErgConfig, Input};
use erg_common::consts::{ERG_MODE, PYTHON_MODE};
use erg_common::dict; use erg_common::dict;
use erg_common::env::{erg_py_external_lib_path, erg_pystd_path, erg_std_path}; use erg_common::env::{erg_py_external_lib_path, erg_pystd_path, erg_std_path};
use erg_common::error::{ErrorCore, Location, SubMessage}; use erg_common::error::{ErrorCore, Location, SubMessage};
@ -523,7 +524,7 @@ impl Context {
) -> Triple<VarInfo, TyCheckError> { ) -> Triple<VarInfo, TyCheckError> {
// get_attr_info(?T, aaa) == None // get_attr_info(?T, aaa) == None
// => ?T(<: Structural({ .aaa = ?U })) // => ?T(<: Structural({ .aaa = ?U }))
if self.in_subr() && cfg!(feature = "py_compat") { if self.in_subr() && PYTHON_MODE {
let t = free_var(self.level, Constraint::new_type_of(Type)); let t = free_var(self.level, Constraint::new_type_of(Type));
if let Some(fv) = obj.ref_t().as_free() { if let Some(fv) = obj.ref_t().as_free() {
if fv.get_sub().is_some() { if fv.get_sub().is_some() {
@ -624,7 +625,7 @@ impl Context {
} }
return Triple::Ok(method.method_info.clone()); return Triple::Ok(method.method_info.clone());
} }
Triple::Err(err) if !cfg!(feature = "py_compat") => { Triple::Err(err) if ERG_MODE => {
return Triple::Err(err); return Triple::Err(err);
} }
_ => {} _ => {}
@ -863,7 +864,7 @@ impl Context {
) -> SingleTyCheckResult<VarInfo> { ) -> SingleTyCheckResult<VarInfo> {
// search_method_info(?T, aaa, pos_args: [1, 2]) == None // search_method_info(?T, aaa, pos_args: [1, 2]) == None
// => ?T(<: Structural({ .aaa = (self: ?T, ?U, ?V) -> ?W })) // => ?T(<: Structural({ .aaa = (self: ?T, ?U, ?V) -> ?W }))
if cfg!(feature = "py_compat") && self.in_subr() { if PYTHON_MODE && self.in_subr() {
let nd_params = pos_args let nd_params = pos_args
.iter() .iter()
.map(|_| ParamTy::Pos(free_var(self.level, Constraint::new_type_of(Type)))) .map(|_| ParamTy::Pos(free_var(self.level, Constraint::new_type_of(Type))))
@ -2497,9 +2498,15 @@ impl Context {
// FIXME: 現在の実装だとimportしたモジュールはどこからでも見れる // FIXME: 現在の実装だとimportしたモジュールはどこからでも見れる
pub(crate) fn get_mod(&self, name: &str) -> Option<&Context> { pub(crate) fn get_mod(&self, name: &str) -> Option<&Context> {
if name == "module" && ERG_MODE {
self.get_module()
} else if name == "global" {
self.get_builtins()
} else {
let t = self.get_var_info(name).map(|(_, vi)| &vi.t)?; let t = self.get_var_info(name).map(|(_, vi)| &vi.t)?;
self.get_mod_from_t(t) self.get_mod_from_t(t)
} }
}
pub fn get_mod_from_t(&self, mod_t: &Type) -> Option<&Context> { pub fn get_mod_from_t(&self, mod_t: &Type) -> Option<&Context> {
self.get_ctx_from_path(&self.get_path_from_mod_t(mod_t)?) self.get_ctx_from_path(&self.get_path_from_mod_t(mod_t)?)
@ -2571,6 +2578,11 @@ impl Context {
} }
pub(crate) fn get_namespace(&self, namespace: &Str) -> Option<&Context> { pub(crate) fn get_namespace(&self, namespace: &Str) -> Option<&Context> {
if &namespace[..] == "global" {
return self.get_builtins();
} else if &namespace[..] == "module" {
return self.get_module();
}
let mut namespaces = namespace.split_with(&[".", "::"]); let mut namespaces = namespace.split_with(&[".", "::"]);
let mut namespace = namespaces.first().map(|n| n.to_string())?; let mut namespace = namespaces.first().map(|n| n.to_string())?;
namespaces.remove(0); namespaces.remove(0);

View file

@ -9,6 +9,7 @@ use erg_common::log;
use erg_common::set::Set; use erg_common::set::Set;
use erg_common::traits::Locational; use erg_common::traits::Locational;
use erg_common::Str; use erg_common::Str;
use erg_parser::ast::VarName;
use crate::feature_error; use crate::feature_error;
use crate::ty::constructors::*; use crate::ty::constructors::*;
@ -34,8 +35,8 @@ use crate::hir;
pub struct TyVarCache { pub struct TyVarCache {
_level: usize, _level: usize,
pub(crate) already_appeared: Set<Str>, pub(crate) already_appeared: Set<Str>,
pub(crate) tyvar_instances: Dict<Str, Type>, pub(crate) tyvar_instances: Dict<VarName, Type>,
pub(crate) typaram_instances: Dict<Str, TyParam>, pub(crate) typaram_instances: Dict<VarName, TyParam>,
pub(crate) structural_inner: bool, pub(crate) structural_inner: bool,
} }
@ -133,7 +134,7 @@ impl TyVarCache {
self.already_appeared.insert(name); self.already_appeared.insert(name);
} }
pub(crate) fn push_or_init_tyvar(&mut self, name: &Str, tv: &Type, ctx: &Context) { pub(crate) fn push_or_init_tyvar(&mut self, name: &VarName, tv: &Type, ctx: &Context) {
if let Some(inst) = self.tyvar_instances.get(name) { if let Some(inst) = self.tyvar_instances.get(name) {
self.update_tyvar(inst, tv, ctx); self.update_tyvar(inst, tv, ctx);
} else if let Some(inst) = self.typaram_instances.get(name) { } else if let Some(inst) = self.typaram_instances.get(name) {
@ -175,7 +176,7 @@ impl TyVarCache {
} }
} }
pub(crate) fn push_or_init_typaram(&mut self, name: &Str, tp: &TyParam, ctx: &Context) { pub(crate) fn push_or_init_typaram(&mut self, name: &VarName, tp: &TyParam, ctx: &Context) {
// FIXME: // FIXME:
if let Some(inst) = self.typaram_instances.get(name) { if let Some(inst) = self.typaram_instances.get(name) {
self.update_typaram(inst, tp, ctx); self.update_typaram(inst, tp, ctx);
@ -262,10 +263,11 @@ impl Context {
} }
Ok(TyParam::t(t)) Ok(TyParam::t(t))
} else { } else {
let varname = VarName::from_str(name.clone());
if tmp_tv_cache.appeared(&name) { if tmp_tv_cache.appeared(&name) {
let tp = let tp =
TyParam::named_free_var(name.clone(), self.level, Constraint::Uninited); TyParam::named_free_var(name.clone(), self.level, Constraint::Uninited);
tmp_tv_cache.push_or_init_typaram(&name, &tp, self); tmp_tv_cache.push_or_init_typaram(&varname, &tp, self);
return Ok(tp); return Ok(tp);
} }
if let Some(tv_cache) = &self.tv_cache { if let Some(tv_cache) = &self.tv_cache {
@ -278,7 +280,7 @@ impl Context {
tmp_tv_cache.push_appeared(name.clone()); tmp_tv_cache.push_appeared(name.clone());
let constr = tmp_tv_cache.instantiate_constraint(constr, self, loc)?; let constr = tmp_tv_cache.instantiate_constraint(constr, self, loc)?;
let tp = TyParam::named_free_var(name.clone(), self.level, constr); let tp = TyParam::named_free_var(name.clone(), self.level, constr);
tmp_tv_cache.push_or_init_typaram(&name, &tp, self); tmp_tv_cache.push_or_init_typaram(&varname, &tp, self);
Ok(tp) Ok(tp)
} }
} }
@ -411,9 +413,10 @@ impl Context {
) )
} }
} else { } else {
let varname = VarName::from_str(name.clone());
if tmp_tv_cache.appeared(&name) { if tmp_tv_cache.appeared(&name) {
let tyvar = named_free_var(name.clone(), self.level, Constraint::Uninited); let tyvar = named_free_var(name.clone(), self.level, Constraint::Uninited);
tmp_tv_cache.push_or_init_tyvar(&name, &tyvar, self); tmp_tv_cache.push_or_init_tyvar(&varname, &tyvar, self);
return Ok(tyvar); return Ok(tyvar);
} }
if let Some(tv_ctx) = &self.tv_cache { if let Some(tv_ctx) = &self.tv_cache {
@ -434,7 +437,7 @@ impl Context {
tmp_tv_cache.push_appeared(name.clone()); tmp_tv_cache.push_appeared(name.clone());
let constr = tmp_tv_cache.instantiate_constraint(constr, self, loc)?; let constr = tmp_tv_cache.instantiate_constraint(constr, self, loc)?;
let tyvar = named_free_var(name.clone(), self.level, constr); let tyvar = named_free_var(name.clone(), self.level, constr);
tmp_tv_cache.push_or_init_tyvar(&name, &tyvar, self); tmp_tv_cache.push_or_init_tyvar(&varname, &tyvar, self);
Ok(tyvar) Ok(tyvar)
} }
} }

View file

@ -10,7 +10,7 @@ use ast::{
NonDefaultParamSignature, ParamTySpec, PolyTypeSpec, PreDeclTypeSpec, TypeBoundSpec, NonDefaultParamSignature, ParamTySpec, PolyTypeSpec, PreDeclTypeSpec, TypeBoundSpec,
TypeBoundSpecs, TypeSpec, TypeBoundSpecs, TypeSpec,
}; };
use erg_parser::ast::{self, ConstArray, Identifier, VisModifierSpec, VisRestriction}; use erg_parser::ast::{self, ConstArray, Identifier, VarName, VisModifierSpec, VisRestriction};
use erg_parser::token::TokenKind; use erg_parser::token::TokenKind;
use erg_parser::Parser; use erg_parser::Parser;
@ -124,7 +124,7 @@ impl Context {
// TODO: other than type `Type` // TODO: other than type `Type`
let constr = Constraint::new_type_of(Type); let constr = Constraint::new_type_of(Type);
let tv = named_free_var(name.inspect().clone(), self.level, constr); let tv = named_free_var(name.inspect().clone(), self.level, constr);
tv_cache.push_or_init_tyvar(name.inspect(), &tv, self); tv_cache.push_or_init_tyvar(name, &tv, self);
Ok(()) Ok(())
} }
TypeBoundSpec::NonDefault { lhs, spec } => { TypeBoundSpec::NonDefault { lhs, spec } => {
@ -146,10 +146,10 @@ impl Context {
}; };
if constr.get_sub_sup().is_none() { if constr.get_sub_sup().is_none() {
let tp = TyParam::named_free_var(lhs.inspect().clone(), self.level, constr); let tp = TyParam::named_free_var(lhs.inspect().clone(), self.level, constr);
tv_cache.push_or_init_typaram(lhs.inspect(), &tp, self); tv_cache.push_or_init_typaram(lhs, &tp, self);
} else { } else {
let tv = named_free_var(lhs.inspect().clone(), self.level, constr); let tv = named_free_var(lhs.inspect().clone(), self.level, constr);
tv_cache.push_or_init_tyvar(lhs.inspect(), &tv, self); tv_cache.push_or_init_tyvar(lhs, &tv, self);
} }
Ok(()) Ok(())
} }
@ -536,7 +536,7 @@ impl Context {
Ok(typ.clone()) Ok(typ.clone())
} else if not_found_is_qvar { } else if not_found_is_qvar {
let tyvar = named_free_var(Str::rc(other), self.level, Constraint::Uninited); let tyvar = named_free_var(Str::rc(other), self.level, Constraint::Uninited);
tmp_tv_cache.push_or_init_tyvar(ident.inspect(), &tyvar, self); tmp_tv_cache.push_or_init_tyvar(&ident.name, &tyvar, self);
Ok(tyvar) Ok(tyvar)
} else { } else {
Err(TyCheckErrors::from(TyCheckError::no_type_error( Err(TyCheckErrors::from(TyCheckError::no_type_error(
@ -559,7 +559,7 @@ impl Context {
tmp_tv_cache: &mut TyVarCache, tmp_tv_cache: &mut TyVarCache,
not_found_is_qvar: bool, not_found_is_qvar: bool,
) -> TyCheckResult<Type> { ) -> TyCheckResult<Type> {
match &poly_spec.ident.inspect()[..] { match poly_spec.acc.to_string().trim_start_matches("::") {
"Array" => { "Array" => {
// TODO: kw // TODO: kw
let mut args = poly_spec.args.pos_args(); let mut args = poly_spec.args.pos_args();
@ -647,13 +647,11 @@ impl Context {
Ok(t.structuralize()) Ok(t.structuralize())
} }
other => { other => {
let ctx = if let Some((_, ctx)) = self.get_type(&Str::rc(other)) { let Some((typ, ctx)) = self.get_type(&Str::rc(other)) else {
ctx
} else {
return Err(TyCheckErrors::from(TyCheckError::no_type_error( return Err(TyCheckErrors::from(TyCheckError::no_type_error(
self.cfg.input.clone(), self.cfg.input.clone(),
line!() as usize, line!() as usize,
poly_spec.ident.loc(), poly_spec.acc.loc(),
self.caused_by(), self.caused_by(),
other, other,
self.get_similar_name(other), self.get_similar_name(other),
@ -680,7 +678,8 @@ impl Context {
self.level, self.level,
Constraint::Uninited, Constraint::Uninited,
); );
tmp_tv_cache.push_or_init_typaram(&name, &tp, self); let varname = VarName::from_str(name);
tmp_tv_cache.push_or_init_typaram(&varname, &tp, self);
Ok(tp) Ok(tp)
} else { } else {
Err(e) Err(e)
@ -711,7 +710,7 @@ impl Context {
} }
} }
// FIXME: non-builtin // FIXME: non-builtin
Ok(poly(Str::rc(other), new_params)) Ok(poly(typ.qual_name(), new_params))
} }
} }
} }
@ -723,6 +722,7 @@ impl Context {
tmp_tv_cache: &mut TyVarCache, tmp_tv_cache: &mut TyVarCache,
not_found_is_qvar: bool, not_found_is_qvar: bool,
) -> TyCheckResult<TyParam> { ) -> TyCheckResult<TyParam> {
self.inc_ref_acc(&acc.clone().downcast(), self);
match acc { match acc {
ast::ConstAccessor::Attr(attr) => { ast::ConstAccessor::Attr(attr) => {
let obj = self.instantiate_const_expr( let obj = self.instantiate_const_expr(
@ -734,14 +734,7 @@ impl Context {
Ok(obj.proj(attr.name.inspect())) Ok(obj.proj(attr.name.inspect()))
} }
ast::ConstAccessor::Local(local) => { ast::ConstAccessor::Local(local) => {
self.inc_ref_local(local, self); self.instantiate_local(local, erased_idx, tmp_tv_cache, local, not_found_is_qvar)
self.instantiate_local(
local.inspect(),
erased_idx,
tmp_tv_cache,
local,
not_found_is_qvar,
)
} }
other => type_feature_error!( other => type_feature_error!(
self, self,
@ -753,13 +746,13 @@ impl Context {
fn instantiate_local( fn instantiate_local(
&self, &self,
name: &Str, name: &Identifier,
erased_idx: Option<(&Context, usize)>, erased_idx: Option<(&Context, usize)>,
tmp_tv_cache: &mut TyVarCache, tmp_tv_cache: &mut TyVarCache,
loc: &impl Locational, loc: &impl Locational,
not_found_is_qvar: bool, not_found_is_qvar: bool,
) -> TyCheckResult<TyParam> { ) -> TyCheckResult<TyParam> {
if &name[..] == "_" { if &name.inspect()[..] == "_" {
let t = if let Some((ctx, i)) = erased_idx { let t = if let Some((ctx, i)) = erased_idx {
let param = ctx.params.get(i).ok_or_else(|| { let param = ctx.params.get(i).ok_or_else(|| {
TyCheckErrors::from(TyCheckError::too_many_args_error( TyCheckErrors::from(TyCheckError::too_many_args_error(
@ -779,15 +772,15 @@ impl Context {
}; };
return Ok(TyParam::erased(t)); return Ok(TyParam::erased(t));
} }
if let Some(tp) = self.get_tp_from_tv_cache(name, tmp_tv_cache) { if let Some(tp) = self.get_tp_from_tv_cache(name.inspect(), tmp_tv_cache) {
return Ok(tp); return Ok(tp);
} }
if let Some(value) = self.rec_get_const_obj(name) { if let Some(value) = self.rec_get_const_obj(name.inspect()) {
return Ok(TyParam::Value(value.clone())); return Ok(TyParam::Value(value.clone()));
} }
if not_found_is_qvar { if not_found_is_qvar {
let tyvar = named_free_var(name.clone(), self.level, Constraint::Uninited); let tyvar = named_free_var(name.inspect().clone(), self.level, Constraint::Uninited);
tmp_tv_cache.push_or_init_tyvar(name, &tyvar, self); tmp_tv_cache.push_or_init_tyvar(&name.name, &tyvar, self);
return Ok(TyParam::t(tyvar)); return Ok(TyParam::t(tyvar));
} }
Err(TyCheckErrors::from(TyCheckError::no_var_error( Err(TyCheckErrors::from(TyCheckError::no_var_error(
@ -795,8 +788,8 @@ impl Context {
line!() as usize, line!() as usize,
loc.loc(), loc.loc(),
self.caused_by(), self.caused_by(),
name, name.inspect(),
self.get_similar_name(name), self.get_similar_name(name.inspect()),
))) )))
} }
@ -814,7 +807,6 @@ impl Context {
} }
match expr { match expr {
ast::ConstExpr::Lit(lit) => Ok(TyParam::Value(self.eval_lit(lit)?)), ast::ConstExpr::Lit(lit) => Ok(TyParam::Value(self.eval_lit(lit)?)),
// TODO: inc_ref
ast::ConstExpr::Accessor(acc) => { ast::ConstExpr::Accessor(acc) => {
self.instantiate_acc(acc, erased_idx, tmp_tv_cache, not_found_is_qvar) self.instantiate_acc(acc, erased_idx, tmp_tv_cache, not_found_is_qvar)
} }

View file

@ -20,6 +20,7 @@ use std::option::Option; // conflicting to Type::Option
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use erg_common::config::ErgConfig; use erg_common::config::ErgConfig;
use erg_common::consts::PYTHON_MODE;
use erg_common::dict::Dict; use erg_common::dict::Dict;
use erg_common::error::Location; use erg_common::error::Location;
use erg_common::impl_display_from_debug; use erg_common::impl_display_from_debug;
@ -68,7 +69,7 @@ impl TryFrom<&str> for ControlKind {
match s { match s {
"if" | "if!" => Ok(ControlKind::If), "if" | "if!" => Ok(ControlKind::If),
"while!" => Ok(ControlKind::While), "while!" => Ok(ControlKind::While),
"while" if cfg!(feature = "py_compat") => Ok(ControlKind::While), "while" if PYTHON_MODE => Ok(ControlKind::While),
"for" | "for!" => Ok(ControlKind::For), "for" | "for!" => Ok(ControlKind::For),
"match" | "match!" => Ok(ControlKind::Match), "match" | "match!" => Ok(ControlKind::Match),
"try" | "try!" => Ok(ControlKind::Try), "try" | "try!" => Ok(ControlKind::Try),
@ -981,6 +982,18 @@ impl Context {
} }
} }
pub(crate) fn get_module(&self) -> Option<&Context> {
self.get_outer()
.and_then(|outer| {
if outer.kind == ContextKind::Module {
Some(outer)
} else {
outer.get_module()
}
})
.or(Some(self))
}
/// This method is intended to be called __only__ in the top-level module. /// This method is intended to be called __only__ in the top-level module.
/// `.cfg` is not initialized and is used around. /// `.cfg` is not initialized and is used around.
pub fn initialize(&mut self) { pub fn initialize(&mut self) {
@ -1016,6 +1029,9 @@ impl Context {
}; };
log!(info "{}: current namespace: {name}", fn_name!()); log!(info "{}: current namespace: {name}", fn_name!());
self.outer = Some(Box::new(mem::take(self))); self.outer = Some(Box::new(mem::take(self)));
if let Some(tv_cache) = tv_cache.as_ref() {
self.assign_bounds(tv_cache)
};
self.cfg = self.get_outer().unwrap().cfg.clone(); self.cfg = self.get_outer().unwrap().cfg.clone();
self.shared = self.get_outer().unwrap().shared.clone(); self.shared = self.get_outer().unwrap().shared.clone();
self.tv_cache = tv_cache; self.tv_cache = tv_cache;

View file

@ -6,6 +6,7 @@ use std::process::{Command, Stdio};
use std::time::SystemTime; use std::time::SystemTime;
use erg_common::config::ErgMode; use erg_common::config::ErgMode;
use erg_common::consts::PYTHON_MODE;
use erg_common::env::erg_pystd_path; use erg_common::env::erg_pystd_path;
use erg_common::erg_util::BUILTIN_ERG_MODS; use erg_common::erg_util::BUILTIN_ERG_MODS;
use erg_common::levenshtein::get_similar_name; use erg_common::levenshtein::get_similar_name;
@ -16,8 +17,11 @@ use erg_common::triple::Triple;
use erg_common::Str; use erg_common::Str;
use erg_common::{get_hash, log, set}; use erg_common::{get_hash, log, set};
use ast::{ConstIdentifier, Decorator, DefId, Identifier, OperationKind, PolyTypeSpec, VarName}; use ast::{
use erg_parser::ast::{self, PreDeclTypeSpec}; ConstIdentifier, Decorator, DefId, Identifier, OperationKind, PolyTypeSpec, PreDeclTypeSpec,
VarName,
};
use erg_parser::ast;
use crate::ty::constructors::{ use crate::ty::constructors::{
free_var, func, func0, func1, proc, ref_, ref_mut, unknown_len_array_t, v_enum, free_var, func, func0, func1, proc, ref_, ref_mut, unknown_len_array_t, v_enum,
@ -256,7 +260,7 @@ impl Context {
self.erg_to_py_names self.erg_to_py_names
.insert(ident.inspect().clone(), py_name.clone()); .insert(ident.inspect().clone(), py_name.clone());
} }
let ident = if cfg!(feature = "py_compat") && py_name.is_some() { let ident = if PYTHON_MODE && py_name.is_some() {
let mut symbol = ident.name.clone().into_token(); let mut symbol = ident.name.clone().into_token();
symbol.content = py_name.clone().unwrap(); symbol.content = py_name.clone().unwrap();
Identifier::new(ident.vis.clone(), VarName::new(symbol)) Identifier::new(ident.vis.clone(), VarName::new(symbol))
@ -344,7 +348,7 @@ impl Context {
opt_decl_t: Option<&ParamTy>, opt_decl_t: Option<&ParamTy>,
kind: ParamKind, kind: ParamKind,
) -> TyCheckResult<()> { ) -> TyCheckResult<()> {
let vis = if cfg!(feature = "py_compat") { let vis = if PYTHON_MODE {
Visibility::BUILTIN_PUBLIC Visibility::BUILTIN_PUBLIC
} else { } else {
Visibility::private(self.name.clone()) Visibility::private(self.name.clone())
@ -552,6 +556,19 @@ impl Context {
} }
} }
pub(crate) fn assign_bounds(&mut self, tv_cache: &TyVarCache) {
for tyvar in tv_cache.tyvar_instances.keys() {
let vi =
VarInfo::nd_parameter(Type::Type, self.absolutize(tyvar.loc()), self.name.clone());
self.locals.insert(tyvar.clone(), vi);
}
for (typaram, tp) in tv_cache.typaram_instances.iter() {
let t = self.get_tp_t(tp).unwrap_or(Type::Obj);
let vi = VarInfo::nd_parameter(t, self.absolutize(typaram.loc()), self.name.clone());
self.locals.insert(typaram.clone(), vi);
}
}
pub(crate) fn assign_params( pub(crate) fn assign_params(
&mut self, &mut self,
params: &mut hir::Params, params: &mut hir::Params,
@ -2003,48 +2020,53 @@ impl Context {
Ok(()) Ok(())
} }
fn inc_ref_acc(&self, acc: &ast::Accessor, namespace: &Context) { pub(crate) fn inc_ref<L: Locational>(&self, vi: &VarInfo, name: &L, namespace: &Context) {
self.index().inc_ref(vi, namespace.absolutize(name.loc()));
}
pub(crate) fn inc_ref_acc(&self, acc: &ast::Accessor, namespace: &Context) -> bool {
match acc { match acc {
ast::Accessor::Ident(ident) => self.inc_ref_local(ident, namespace), ast::Accessor::Ident(ident) => self.inc_ref_local(ident, namespace),
ast::Accessor::Attr(attr) => { ast::Accessor::Attr(attr) => {
self.inc_ref_expr(&attr.obj, namespace); self.inc_ref_expr(&attr.obj, namespace);
if let Ok(ctxs) = self.get_singular_ctxs(&attr.obj, self) { if let Ok(ctxs) = self.get_singular_ctxs(&attr.obj, self) {
if let Some(first) = ctxs.first() { for ctx in ctxs {
first.inc_ref_local(&attr.ident, namespace); if ctx.inc_ref_local(&attr.ident, namespace) {
return true;
} }
} }
} }
_ => {} false
}
_ => false,
} }
} }
fn inc_ref_expr(&self, expr: &ast::Expr, namespace: &Context) { pub(crate) fn inc_ref_predecl_typespec(
#[allow(clippy::single_match)] &self,
match expr { predecl: &PreDeclTypeSpec,
ast::Expr::Accessor(acc) => self.inc_ref_acc(acc, namespace), namespace: &Context,
// TODO: ) -> bool {
_ => {}
}
}
pub(crate) fn inc_ref_predecl_typespec(&self, predecl: &PreDeclTypeSpec, namespace: &Context) {
match predecl { match predecl {
PreDeclTypeSpec::Mono(mono) => self.inc_ref_mono_typespec(mono, namespace), PreDeclTypeSpec::Mono(mono) => self.inc_ref_mono_typespec(mono, namespace),
PreDeclTypeSpec::Poly(poly) => self.inc_ref_poly_typespec(poly, namespace), PreDeclTypeSpec::Poly(poly) => self.inc_ref_poly_typespec(poly, namespace),
PreDeclTypeSpec::Attr { namespace: obj, t } => { PreDeclTypeSpec::Attr { namespace: obj, t } => {
self.inc_ref_expr(obj, namespace); self.inc_ref_expr(obj, namespace);
if let Ok(ctxs) = self.get_singular_ctxs(obj, self) { if let Ok(ctxs) = self.get_singular_ctxs(obj, self) {
if let Some(first) = ctxs.first() { for ctx in ctxs {
first.inc_ref_mono_typespec(t, namespace); if ctx.inc_ref_mono_typespec(t, namespace) {
return true;
} }
} }
} }
false
}
// TODO: // TODO:
_ => {} _ => false,
} }
} }
pub(crate) fn inc_ref_mono_typespec(&self, ident: &Identifier, namespace: &Context) { fn inc_ref_mono_typespec(&self, ident: &Identifier, namespace: &Context) -> bool {
if let Triple::Ok(vi) = self.rec_get_var_info( if let Triple::Ok(vi) = self.rec_get_var_info(
ident, ident,
crate::compile::AccessKind::Name, crate::compile::AccessKind::Name,
@ -2052,22 +2074,18 @@ impl Context {
self, self,
) { ) {
self.inc_ref(&vi, &ident.name, namespace); self.inc_ref(&vi, &ident.name, namespace);
true
} else {
false
} }
} }
/// TODO: /// TODO: params
pub(crate) fn inc_ref_poly_typespec(&self, poly: &PolyTypeSpec, namespace: &Context) { fn inc_ref_poly_typespec(&self, poly: &PolyTypeSpec, namespace: &Context) -> bool {
if let Triple::Ok(vi) = self.rec_get_var_info( self.inc_ref_acc(&poly.acc.clone().downcast(), namespace)
&poly.ident,
crate::compile::AccessKind::Name,
&self.cfg.input,
self,
) {
self.inc_ref(&vi, &poly.ident.name, namespace);
}
} }
pub(crate) fn inc_ref_local(&self, local: &ConstIdentifier, namespace: &Context) { fn inc_ref_local(&self, local: &ConstIdentifier, namespace: &Context) -> bool {
if let Triple::Ok(vi) = self.rec_get_var_info( if let Triple::Ok(vi) = self.rec_get_var_info(
local, local,
crate::compile::AccessKind::Name, crate::compile::AccessKind::Name,
@ -2075,10 +2093,18 @@ impl Context {
self, self,
) { ) {
self.inc_ref(&vi, &local.name, namespace); self.inc_ref(&vi, &local.name, namespace);
true
} else {
&local.inspect()[..] == "module" || &local.inspect()[..] == "global"
} }
} }
pub fn inc_ref<L: Locational>(&self, vi: &VarInfo, name: &L, namespace: &Context) { fn inc_ref_expr(&self, expr: &ast::Expr, namespace: &Context) -> bool {
self.index().inc_ref(vi, namespace.absolutize(name.loc())); #[allow(clippy::single_match)]
match expr {
ast::Expr::Accessor(acc) => self.inc_ref_acc(acc, namespace),
// TODO:
_ => false,
}
} }
} }

View file

@ -1,3 +1,4 @@
use erg_common::consts::PYTHON_MODE;
use erg_common::traits::{Locational, Runnable, Stream}; use erg_common::traits::{Locational, Runnable, Stream};
use erg_common::{enum_unwrap, fn_name, log, set, Str}; use erg_common::{enum_unwrap, fn_name, log, set, Str};
@ -562,7 +563,7 @@ impl ASTLowerer {
Some(py_name.clone()), Some(py_name.clone()),
self.module.context.absolutize(ident.name.loc()), self.module.context.absolutize(ident.name.loc()),
); );
let name = if cfg!(feature = "py_compat") { let name = if PYTHON_MODE {
let mut symbol = ident.name.clone().into_token(); let mut symbol = ident.name.clone().into_token();
symbol.content = py_name.clone(); symbol.content = py_name.clone();
VarName::new(symbol) VarName::new(symbol)
@ -571,7 +572,7 @@ impl ASTLowerer {
}; };
self.module.context.decls.insert(name, vi); self.module.context.decls.insert(name, vi);
} }
let new_ident = if cfg!(feature = "py_compat") { let new_ident = if PYTHON_MODE {
let mut symbol = ident.name.clone().into_token(); let mut symbol = ident.name.clone().into_token();
symbol.content = py_name.clone(); symbol.content = py_name.clone();
Identifier::new(ident.vis.clone(), VarName::new(symbol)) Identifier::new(ident.vis.clone(), VarName::new(symbol))
@ -610,7 +611,7 @@ impl ASTLowerer {
if ident.is_raw() { if ident.is_raw() {
return Ok(()); return Ok(());
} }
let name = if cfg!(feature = "py_compat") { let name = if PYTHON_MODE {
self.module self.module
.context .context
.erg_to_py_names .erg_to_py_names

View file

@ -550,6 +550,32 @@ impl LowerError {
) )
} }
pub fn shadow_special_namespace_error(
input: Input,
errno: usize,
loc: Location,
caused_by: String,
name: &str,
) -> Self {
let name = StyledStr::new(readable_name(name), Some(WARN), Some(ATTR));
Self::new(
ErrorCore::new(
vec![SubMessage::only_loc(loc)],
switch_lang!(
"japanese" => format!("特殊名前空間{name}と同名の変数は定義できません"),
"simplified_chinese" => format!("不能定义与特殊命名空间{name}同名的变量"),
"traditional_chinese" => format!("不能定義與特殊命名空間{name}同名的變量"),
"english" => format!("cannot define variable with the same name as special namespace {name}"),
),
errno,
AssignError,
loc,
),
input,
caused_by,
)
}
pub fn reassign_error( pub fn reassign_error(
input: Input, input: Input,
errno: usize, errno: usize,

View file

@ -4,17 +4,27 @@
.Hashable: ClassType .Hashable: ClassType
.Sized: ClassType .Sized: ClassType
.Callable: ClassType .Callable: ClassType
.Callable.
__getitem__: (params: [Type; _], Type) -> Type
.Iterable: ClassType .Iterable: ClassType
.Iterable.
__getitem__: Type -> Type
.Collection: ClassType .Collection: ClassType
.Iterator: ClassType .Iterator: ClassType
.Iterator.
__getitem__: Type -> Type
.Reversible: ClassType .Reversible: ClassType
.Genertor: ClassType .Genertor: ClassType
.Sequence: ClassType .Sequence: ClassType
.Sequence.
__getitem__: Type -> Type
.MutableSqunce: ClassType .MutableSqunce: ClassType
.ByteString: ClassType .ByteString: ClassType
.Set: ClassType .Set: ClassType
.MutableSet: ClassType .MutableSet: ClassType
.Mapping: ClassType .Mapping: ClassType
.Mapping.
__getitem__: (Type, Type) -> Type
.MutableMapping: ClassType .MutableMapping: ClassType
.MappingView: ClassType .MappingView: ClassType
.ItemsView: ClassType .ItemsView: ClassType

View file

@ -4,6 +4,7 @@
use std::mem; use std::mem;
use erg_common::config::{ErgConfig, ErgMode}; use erg_common::config::{ErgConfig, ErgMode};
use erg_common::consts::{ERG_MODE, PYTHON_MODE};
use erg_common::dict; use erg_common::dict;
use erg_common::dict::Dict; use erg_common::dict::Dict;
use erg_common::error::{Location, MultiErrorDisplay}; use erg_common::error::{Location, MultiErrorDisplay};
@ -280,7 +281,7 @@ impl ASTLowerer {
(false, false) => { (false, false) => {
if let hir::Expr::TypeAsc(type_asc) = &elem { if let hir::Expr::TypeAsc(type_asc) = &elem {
// e.g. [1, "a": Str or NoneType] // e.g. [1, "a": Str or NoneType]
if !cfg!(feature = "py_compat") if ERG_MODE
&& !self && !self
.module .module
.context .context
@ -288,7 +289,7 @@ impl ASTLowerer {
{ {
return Err(self.elem_err(&l, &r, &elem)); return Err(self.elem_err(&l, &r, &elem));
} // else(OK): e.g. [1, "a": Str or Int] } // else(OK): e.g. [1, "a": Str or Int]
} else if !cfg!(feature = "py_compat") { } else if ERG_MODE {
return Err(self.elem_err(&l, &r, &elem)); return Err(self.elem_err(&l, &r, &elem));
} }
} }
@ -399,7 +400,7 @@ impl ASTLowerer {
for elem in elems { for elem in elems {
let elem = self.lower_expr(elem.expr)?; let elem = self.lower_expr(elem.expr)?;
union = self.module.context.union(&union, elem.ref_t()); union = self.module.context.union(&union, elem.ref_t());
if !cfg!(feature = "py_compat") && union.is_union_type() { if ERG_MODE && union.is_union_type() {
return Err(LowerErrors::from(LowerError::syntax_error( return Err(LowerErrors::from(LowerError::syntax_error(
self.cfg.input.clone(), self.cfg.input.clone(),
line!() as usize, line!() as usize,
@ -515,7 +516,7 @@ impl ASTLowerer {
let key = self.lower_expr(kv.key)?; let key = self.lower_expr(kv.key)?;
let value = self.lower_expr(kv.value)?; let value = self.lower_expr(kv.value)?;
if let Some(popped_val_t) = union.insert(key.t(), value.t()) { if let Some(popped_val_t) = union.insert(key.t(), value.t()) {
if cfg!(feature = "py_compat") { if PYTHON_MODE {
let val_t = union.get_mut(key.ref_t()).unwrap(); let val_t = union.get_mut(key.ref_t()).unwrap();
*val_t = self.module.context.union(&mem::take(val_t), &popped_val_t); *val_t = self.module.context.union(&mem::take(val_t), &popped_val_t);
} else { } else {
@ -1146,7 +1147,7 @@ impl ASTLowerer {
fn lower_lambda(&mut self, lambda: ast::Lambda) -> LowerResult<hir::Lambda> { fn lower_lambda(&mut self, lambda: ast::Lambda) -> LowerResult<hir::Lambda> {
log!(info "entered {}({lambda})", fn_name!()); log!(info "entered {}({lambda})", fn_name!());
let in_statement = cfg!(feature = "py_compat") let in_statement = PYTHON_MODE
&& self && self
.module .module
.context .context
@ -1335,7 +1336,17 @@ impl ASTLowerer {
} else { } else {
Str::ever("<lambda>") Str::ever("<lambda>")
}; };
if self if ERG_MODE && (&name[..] == "module" || &name[..] == "global") {
return Err(LowerErrors::from(
LowerError::shadow_special_namespace_error(
self.cfg.input.clone(),
line!() as usize,
def.sig.loc(),
self.module.context.caused_by(),
&name,
),
));
} else if self
.module .module
.context .context
.registered_info(&name, def.sig.is_const()) .registered_info(&name, def.sig.is_const())

View file

@ -1437,15 +1437,14 @@ impl ConstSubscript {
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum ConstAccessor { pub enum ConstAccessor {
Local(ConstIdentifier), Local(ConstIdentifier),
SelfDot(ConstIdentifier),
Attr(ConstAttribute), Attr(ConstAttribute),
TupleAttr(ConstTupleAttribute), TupleAttr(ConstTupleAttribute),
Subscr(ConstSubscript), Subscr(ConstSubscript),
} }
impl_nested_display_for_enum!(ConstAccessor; Local, SelfDot, Attr, TupleAttr, Subscr); impl_nested_display_for_enum!(ConstAccessor; Local, Attr, TupleAttr, Subscr);
impl_display_from_nested!(ConstAccessor); impl_display_from_nested!(ConstAccessor);
impl_locational_for_enum!(ConstAccessor; Local, SelfDot, Attr, TupleAttr, Subscr); impl_locational_for_enum!(ConstAccessor; Local, Attr, TupleAttr, Subscr);
impl ConstAccessor { impl ConstAccessor {
pub const fn local(symbol: Token) -> Self { pub const fn local(symbol: Token) -> Self {
@ -2165,31 +2164,31 @@ impl ConstArgs {
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct PolyTypeSpec { pub struct PolyTypeSpec {
pub ident: Identifier, pub acc: ConstAccessor,
pub args: ConstArgs, // args can be nested (e.g. Vec Vec Int) pub args: ConstArgs, // args can be nested (e.g. Vec Vec Int)
} }
impl fmt::Display for PolyTypeSpec { impl fmt::Display for PolyTypeSpec {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}({})", self.ident, self.args) write!(f, "{}({})", self.acc, self.args)
} }
} }
impl Locational for PolyTypeSpec { impl Locational for PolyTypeSpec {
fn loc(&self) -> Location { fn loc(&self) -> Location {
if let Some(last) = self.args.kw_args.last() { if let Some(last) = self.args.kw_args.last() {
Location::concat(&self.ident, last) Location::concat(&self.acc, last)
} else if let Some(last) = self.args.pos_args.last() { } else if let Some(last) = self.args.pos_args.last() {
Location::concat(&self.ident, last) Location::concat(&self.acc, last)
} else { } else {
self.ident.loc() self.acc.loc()
} }
} }
} }
impl PolyTypeSpec { impl PolyTypeSpec {
pub const fn new(ident: Identifier, args: ConstArgs) -> Self { pub const fn new(acc: ConstAccessor, args: ConstArgs) -> Self {
Self { ident, args } Self { acc, args }
} }
} }
@ -2253,6 +2252,10 @@ impl PreDeclTypeSpec {
t, t,
} }
} }
pub fn poly(acc: ConstAccessor, args: ConstArgs) -> Self {
Self::Poly(PolyTypeSpec::new(acc, args))
}
} }
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@ -2586,8 +2589,8 @@ impl TypeSpec {
Self::PreDeclTy(PreDeclTypeSpec::Mono(ident)) Self::PreDeclTy(PreDeclTypeSpec::Mono(ident))
} }
pub fn poly(ident: Identifier, args: ConstArgs) -> Self { pub fn poly(acc: ConstAccessor, args: ConstArgs) -> Self {
Self::PreDeclTy(PreDeclTypeSpec::Poly(PolyTypeSpec::new(ident, args))) Self::PreDeclTy(PreDeclTypeSpec::Poly(PolyTypeSpec::new(acc, args)))
} }
} }
@ -2632,11 +2635,11 @@ impl TypeSpecWithOp {
pub enum TypeBoundSpec { pub enum TypeBoundSpec {
Omitted(VarName), Omitted(VarName),
NonDefault { NonDefault {
lhs: Token, lhs: VarName,
spec: TypeSpecWithOp, spec: TypeSpecWithOp,
}, },
WithDefault { WithDefault {
lhs: Token, lhs: VarName,
spec: Box<TypeSpecWithOp>, spec: Box<TypeSpecWithOp>,
default: ConstExpr, default: ConstExpr,
}, // e.g. S: Show := Str }, // e.g. S: Show := Str
@ -2646,9 +2649,9 @@ impl NestedDisplay for TypeBoundSpec {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result { fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
match self { match self {
Self::Omitted(name) => write!(f, "{name}"), Self::Omitted(name) => write!(f, "{name}"),
Self::NonDefault { lhs, spec } => write!(f, "{}{spec}", lhs.content), Self::NonDefault { lhs, spec } => write!(f, "{lhs} {spec}"),
Self::WithDefault { lhs, spec, default } => { Self::WithDefault { lhs, spec, default } => {
write!(f, "{}{} := {}", lhs.content, spec, default) write!(f, "{lhs} {spec} := {default}")
} }
} }
} }
@ -2667,9 +2670,17 @@ impl Locational for TypeBoundSpec {
} }
impl TypeBoundSpec { impl TypeBoundSpec {
pub fn non_default(lhs: Token, spec: TypeSpecWithOp) -> Self { pub fn non_default(lhs: VarName, spec: TypeSpecWithOp) -> Self {
Self::NonDefault { lhs, spec } Self::NonDefault { lhs, spec }
} }
pub fn default(lhs: VarName, spec: TypeSpecWithOp, default: ConstExpr) -> Self {
Self::WithDefault {
lhs,
spec: Box::new(spec),
default,
}
}
} }
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]

View file

@ -348,7 +348,7 @@ impl Parser {
self.errs.push(err); self.errs.push(err);
return Err(()); return Err(());
}; };
let bound = TypeBoundSpec::non_default(lhs.name.into_token(), tasc.t_spec); let bound = TypeBoundSpec::non_default(lhs.name, tasc.t_spec);
Ok(bound) Ok(bound)
} }
Expr::Accessor(Accessor::Ident(ident)) => { Expr::Accessor(Accessor::Ident(ident)) => {

View file

@ -1887,11 +1887,7 @@ impl Parser {
let mut call_or_acc = self.try_reduce_acc_chain(acc, in_type_args)?; let mut call_or_acc = self.try_reduce_acc_chain(acc, in_type_args)?;
while let Some(res) = self.opt_reduce_args(in_type_args) { while let Some(res) = self.opt_reduce_args(in_type_args) {
let args = res.map_err(|_| self.stack_dec(fn_name!()))?; let args = res.map_err(|_| self.stack_dec(fn_name!()))?;
let (receiver, attr_name) = match call_or_acc { let call = call_or_acc.call(args);
Expr::Accessor(Accessor::Attr(attr)) => (*attr.obj, Some(attr.ident)),
other => (other, None),
};
let call = Call::new(receiver, attr_name, args);
call_or_acc = Expr::Call(call); call_or_acc = Expr::Call(call);
} }
debug_exit_info!(self); debug_exit_info!(self);

View file

@ -221,10 +221,15 @@ impl Parser {
let const_expr = Self::validate_const_expr(arg.expr)?; let const_expr = Self::validate_const_expr(arg.expr)?;
kw_args.push(ConstKwArg::new(arg.keyword, const_expr)); kw_args.push(ConstKwArg::new(arg.keyword, const_expr));
} }
Ok(PreDeclTypeSpec::Poly(PolyTypeSpec::new( let acc = if let Some(attr) = call.attr_name {
ident, ConstAccessor::attr(ConstExpr::Accessor(ConstAccessor::Local(ident)), attr)
} else {
ConstAccessor::Local(ident)
};
Ok(PreDeclTypeSpec::poly(
acc,
ConstArgs::new(pos_args, var_args, kw_args, paren), ConstArgs::new(pos_args, var_args, kw_args, paren),
))) ))
} }
other => { other => {
let err = ParseError::simple_syntax_error(line!() as usize, other.loc()); let err = ParseError::simple_syntax_error(line!() as usize, other.loc());

View file

@ -62,6 +62,40 @@ if x.is_zero(), do:
assert x == 0 assert x == 0
``` ```
Even when shadowing is performed, you can still refer to the outer variable by its "fully qualified name".
A fully qualified name is a form of name that explicitly specifies the namespace to which the variable belongs.
```erg
x = 0
if True, do: if
x = 1
assert x == 1
assert module::x == 0
C = Class()
x = 2
f() =
x = 3
assert C::x == 2
assert C::f::x == 3
```
Variables defined directly under a module belong to a special namespace called `module`. So you can refer to it as `module::x` and so on.
The special namespace includes `module`, which refers to the module itself, and `global`, which refers to the global namespace.
```erg
print! = None
global::print! "Hello, world!"
```
These namespaces cannot be shadowed. Thus, if you specify ``module::x``, ``global::print!``, etc., it will always point to the same object.
```erg,compile_fail
global = None # ERR, cannot shadow the global namespace
```
## Constants ## Constants
Constants are also a type of algebra. If you start an identifier with a capital letter, it is treated as a constant. They are called constants because once defined, they do not change. Constants are also a type of algebra. If you start an identifier with a capital letter, it is treated as a constant. They are called constants because once defined, they do not change.

View file

@ -68,6 +68,40 @@ if x.is_zero(), do:
assert x == 0 assert x == 0
``` ```
シャドーイングが行われた場合でも、「完全修飾名」で外側の変数を参照することが出来ます。
完全修飾名とは、変数の属する名前空間を明示的に指定した形の名前のことです。
```erg
x = 0
if True, do:
x = 1
assert x == 1
assert module::x == 0
C = Class()
x = 2
f() =
x = 3
assert C::x == 2
assert C::f::x == 3
```
モジュール直下で定義された変数は、`module`という特殊な名前空間に属します。なので、`module::x`などのように参照できます。
特殊な名前空間には、モジュール自身を指す`module`と、グローバル名前空間を指す`global`があります。
```erg
print! = None
global::print! "Hello, world!"
```
これらの名前空間はシャドーイングすることが出来ません。よって、`module::x``global::print!`などと指定すれば、それは常に同じものを指します。
```erg,compile_fail
global = None # ERR, cannot shadow global namespace
```
## 定数 ## 定数
定数も代数の一種です。識別子を大文字で始めると定数として扱われます。一度定義したら変わらないので、定数と呼ばれます。 定数も代数の一種です。識別子を大文字で始めると定数として扱われます。一度定義したら変わらないので、定数と呼ばれます。