mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-28 20:14:45 +00:00
feat: add special namespaces module/global
This commit is contained in:
parent
c4a0efae08
commit
730886021e
29 changed files with 349 additions and 193 deletions
|
@ -1,3 +1,4 @@
|
|||
use erg_common::consts::PYTHON_MODE;
|
||||
use lsp_types::CompletionResponse;
|
||||
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());
|
||||
item.sort_text = Some(format!("{}_{}", CompletionOrder::STD_ITEM, item.label));
|
||||
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")
|
||||
} else {
|
||||
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.kind = Some(CompletionItemKind::MODULE);
|
||||
let import = if cfg!(feature = "py_compat") {
|
||||
let import = if PYTHON_MODE {
|
||||
format!("import {mod_name}\n")
|
||||
} else {
|
||||
format!("{mod_name} = pyimport \"{mod_name}\"\n")
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use erg_common::consts::PYTHON_MODE;
|
||||
use erg_common::traits::{Locational, Stream};
|
||||
use erg_compiler::artifact::BuildRunnable;
|
||||
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)) {
|
||||
(Some(path), Some(range)) => {
|
||||
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
|
||||
.file_cache
|
||||
.get_line(&def_uri, 0)
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use erg_common::consts::ERG_MODE;
|
||||
use erg_common::traits::Locational;
|
||||
use erg_common::Str;
|
||||
use erg_compiler::erg_parser::token::Token;
|
||||
|
@ -25,7 +26,7 @@ impl<'a> HIRVisitor<'a> {
|
|||
hir,
|
||||
file_cache,
|
||||
uri,
|
||||
strict_cmp: !cfg!(feature = "py_compat"),
|
||||
strict_cmp: ERG_MODE,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use erg_common::consts::PYTHON_MODE;
|
||||
use erg_common::lang::LanguageCode;
|
||||
use erg_common::trim_eliminate_top_indent;
|
||||
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::util::{self, NormalizedUrl};
|
||||
|
||||
const PROG_LANG: &str = if cfg!(feature = "py_compat") {
|
||||
"python"
|
||||
} else {
|
||||
"erg"
|
||||
};
|
||||
const PROG_LANG: &str = if PYTHON_MODE { "python" } else { "erg" };
|
||||
|
||||
const ERG_LANG: &str = "erg";
|
||||
|
||||
|
@ -223,7 +220,9 @@ impl<Checker: BuildRunnable> Server<Checker> {
|
|||
}
|
||||
};
|
||||
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 Some(stream) = self.file_cache.get_token_stream(&def_uri) else {
|
||||
return Ok(());
|
||||
|
|
|
@ -130,7 +130,7 @@ impl ASTSemanticState {
|
|||
|
||||
fn gen_from_poly_typespec(&mut self, t_spec: PolyTypeSpec) -> Vec<SemanticToken> {
|
||||
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
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ use std::ops::Not;
|
|||
use std::path::{Path, PathBuf};
|
||||
use std::str::FromStr;
|
||||
|
||||
use erg_common::consts::PYTHON_MODE;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::json;
|
||||
use serde_json::Value;
|
||||
|
@ -227,7 +228,7 @@ impl<Checker: BuildRunnable> Server<Checker> {
|
|||
}
|
||||
|
||||
pub const fn mode(&self) -> &str {
|
||||
if cfg!(feature = "py_compat") {
|
||||
if PYTHON_MODE {
|
||||
"pylyzer"
|
||||
} else {
|
||||
"erg"
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
pub const SEMVER: &str = env!("CARGO_PKG_VERSION");
|
||||
pub const GIT_HASH_SHORT: &str = env!("GIT_HASH_SHORT");
|
||||
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");
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use std::str::FromStr;
|
||||
|
||||
use crate::consts::{ERG_MODE, PYTHON_MODE};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum LanguageCode {
|
||||
English,
|
||||
|
@ -107,8 +109,8 @@ impl LanguageCode {
|
|||
Self::Japanese => cfg!(feature = "japanese"),
|
||||
Self::SimplifiedChinese => cfg!(feature = "simplified_chinese"),
|
||||
Self::TraditionalChinese => cfg!(feature = "traditional_chinese"),
|
||||
Self::Erg => !cfg!(feature = "py_compat"),
|
||||
Self::Python => cfg!(feature = "py_compat"),
|
||||
Self::Erg => ERG_MODE,
|
||||
Self::Python => PYTHON_MODE,
|
||||
Self::ErgOrPython => true,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1372,7 +1372,8 @@ impl Context {
|
|||
t.clone()
|
||||
} else {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -1397,7 +1398,8 @@ impl Context {
|
|||
tp.clone()
|
||||
} else {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use erg_common::consts::{ERG_MODE, PYTHON_MODE};
|
||||
#[allow(unused_imports)]
|
||||
use erg_common::log;
|
||||
use erg_common::Str as StrStruct;
|
||||
|
@ -16,7 +17,7 @@ use Mutability::*;
|
|||
|
||||
impl Context {
|
||||
pub(super) fn init_builtin_classes(&mut self) {
|
||||
let vis = if cfg!(feature = "py_compat") {
|
||||
let vis = if PYTHON_MODE {
|
||||
Visibility::BUILTIN_PUBLIC
|
||||
} else {
|
||||
Visibility::BUILTIN_PRIVATE
|
||||
|
@ -1155,7 +1156,7 @@ impl Context {
|
|||
let mut module = Self::builtin_poly_class(MODULE, vec![PS::named_nd(PATH, Str)], 2);
|
||||
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);
|
||||
if !cfg!(feature = "py_compat") {
|
||||
if ERG_MODE {
|
||||
py_module.register_superclass(g_module_t.clone(), &generic_module);
|
||||
}
|
||||
/* GenericArray */
|
||||
|
@ -2178,32 +2179,16 @@ impl Context {
|
|||
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_type(mono(RECORD), vec![], record, Visibility::BUILTIN_PRIVATE, Const);
|
||||
let name = if cfg!(feature = "py_compat") {
|
||||
FUNC_INT
|
||||
} else {
|
||||
INT
|
||||
};
|
||||
let name = if PYTHON_MODE { FUNC_INT } else { INT };
|
||||
self.register_builtin_type(Int, int, vis.clone(), Const, Some(name));
|
||||
self.register_builtin_type(Nat, nat, vis.clone(), Const, Some(NAT));
|
||||
let name = if cfg!(feature = "py_compat") {
|
||||
FUNC_FLOAT
|
||||
} else {
|
||||
FLOAT
|
||||
};
|
||||
let name = if PYTHON_MODE { FUNC_FLOAT } else { FLOAT };
|
||||
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(Ratio, ratio, vis.clone(), Const, Some(RATIO));
|
||||
let name = if cfg!(feature = "py_compat") {
|
||||
FUNC_BOOL
|
||||
} else {
|
||||
BOOL
|
||||
};
|
||||
let name = if PYTHON_MODE { FUNC_BOOL } else { BOOL };
|
||||
self.register_builtin_type(Bool, bool_, vis.clone(), Const, Some(name));
|
||||
let name = if cfg!(feature = "py_compat") {
|
||||
FUNC_STR
|
||||
} else {
|
||||
STR
|
||||
};
|
||||
let name = if PYTHON_MODE { FUNC_STR } else { STR };
|
||||
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(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(FUNC), func, vis.clone(), Const, Some(FUNC));
|
||||
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(
|
||||
mono(MUTABLE_OBJ),
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use erg_common::consts::{DEBUG_MODE, ERG_MODE, PYTHON_MODE};
|
||||
#[allow(unused_imports)]
|
||||
use erg_common::log;
|
||||
|
||||
|
@ -14,7 +15,7 @@ use Mutability::*;
|
|||
|
||||
impl Context {
|
||||
pub(super) fn init_builtin_funcs(&mut self) {
|
||||
let vis = if cfg!(feature = "py_compat") {
|
||||
let vis = if PYTHON_MODE {
|
||||
Visibility::BUILTIN_PUBLIC
|
||||
} else {
|
||||
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_SUM, t_sum, Immutable, vis.clone(), Some(FUNC_SUM));
|
||||
self.register_builtin_py_impl(FUNC_ZIP, t_zip, Immutable, vis.clone(), Some(FUNC_ZIP));
|
||||
let name = if cfg!(feature = "py_compat") {
|
||||
FUNC_INT
|
||||
} else {
|
||||
FUNC_INT__
|
||||
};
|
||||
let name = if PYTHON_MODE { FUNC_INT } else { FUNC_INT__ };
|
||||
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(
|
||||
PY,
|
||||
t_pyimport.clone(),
|
||||
|
@ -362,7 +359,7 @@ impl Context {
|
|||
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_DISCARD,
|
||||
|
@ -467,7 +464,7 @@ impl Context {
|
|||
}
|
||||
|
||||
pub(super) fn init_builtin_const_funcs(&mut self) {
|
||||
let vis = if cfg!(feature = "py_compat") {
|
||||
let vis = if PYTHON_MODE {
|
||||
Visibility::BUILTIN_PUBLIC
|
||||
} else {
|
||||
Visibility::BUILTIN_PRIVATE
|
||||
|
|
|
@ -13,6 +13,7 @@ mod traits;
|
|||
use std::path::PathBuf;
|
||||
|
||||
use erg_common::config::ErgConfig;
|
||||
use erg_common::consts::{DEBUG_MODE, ERG_MODE, PYTHON_MODE};
|
||||
use erg_common::dict;
|
||||
use erg_common::error::Location;
|
||||
use erg_common::fresh::fresh_varname;
|
||||
|
@ -501,7 +502,7 @@ impl Context {
|
|||
vis: Visibility,
|
||||
py_name: Option<&'static str>,
|
||||
) {
|
||||
if cfg!(feature = "debug") {
|
||||
if DEBUG_MODE {
|
||||
if let Type::Subr(subr) = &t {
|
||||
if subr.has_qvar() {
|
||||
panic!("not quantified subr: {subr}");
|
||||
|
@ -513,7 +514,7 @@ impl Context {
|
|||
} else {
|
||||
None
|
||||
};
|
||||
let name = if cfg!(feature = "py_compat") {
|
||||
let name = if PYTHON_MODE {
|
||||
if let Some(py_name) = py_name {
|
||||
VarName::from_static(py_name)
|
||||
} else {
|
||||
|
@ -603,7 +604,7 @@ impl Context {
|
|||
vis: Visibility,
|
||||
py_name: Option<&'static str>,
|
||||
) {
|
||||
let name = if cfg!(feature = "py_compat") {
|
||||
let name = if PYTHON_MODE {
|
||||
if let Some(py_name) = py_name {
|
||||
VarName::from_static(py_name)
|
||||
} else {
|
||||
|
@ -622,7 +623,7 @@ impl Context {
|
|||
py_name: Option<&'static str>,
|
||||
lineno: u32,
|
||||
) {
|
||||
let name = if cfg!(feature = "py_compat") {
|
||||
let name = if PYTHON_MODE {
|
||||
if let Some(py_name) = py_name {
|
||||
VarName::from_static(py_name)
|
||||
} else {
|
||||
|
@ -631,7 +632,7 @@ impl Context {
|
|||
} else {
|
||||
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
|
||||
} else {
|
||||
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 })))
|
||||
.collect();
|
||||
let meta_t = func(params, None, vec![], v_enum(set! { val.clone() })).quantify();
|
||||
if !cfg!(feature = "py_compat") {
|
||||
if ERG_MODE {
|
||||
self.locals.insert(
|
||||
name.clone(),
|
||||
VarInfo::new(
|
||||
|
@ -897,7 +898,7 @@ impl Context {
|
|||
}
|
||||
|
||||
fn init_builtin_consts(&mut self) {
|
||||
let vis = if cfg!(feature = "py_compat") {
|
||||
let vis = if PYTHON_MODE {
|
||||
Visibility::BUILTIN_PUBLIC
|
||||
} else {
|
||||
Visibility::BUILTIN_PRIVATE
|
||||
|
@ -956,7 +957,7 @@ impl Context {
|
|||
ctx.init_builtin_funcs();
|
||||
ctx.init_builtin_const_funcs();
|
||||
ctx.init_builtin_procs();
|
||||
if cfg!(feature = "py_compat") {
|
||||
if PYTHON_MODE {
|
||||
ctx.init_py_compat_builtin_operators();
|
||||
} else {
|
||||
ctx.init_builtin_operators();
|
||||
|
|
|
@ -13,7 +13,7 @@ use Mutability::*;
|
|||
|
||||
impl Context {
|
||||
pub(super) fn init_builtin_procs(&mut self) {
|
||||
let vis = if cfg!(feature = "py_compat") {
|
||||
let vis = if PYTHON_MODE {
|
||||
Visibility::BUILTIN_PUBLIC
|
||||
} else {
|
||||
Visibility::BUILTIN_PRIVATE
|
||||
|
@ -73,7 +73,7 @@ impl Context {
|
|||
T.clone(),
|
||||
)
|
||||
.quantify();
|
||||
let t_cond = if cfg!(feature = "py_compat") {
|
||||
let t_cond = if PYTHON_MODE {
|
||||
Bool
|
||||
} else {
|
||||
// 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!"),
|
||||
)
|
||||
.quantify();
|
||||
let C = if cfg!(feature = "py_compat") {
|
||||
let C = if PYTHON_MODE {
|
||||
mono("ContextManager").structuralize()
|
||||
} else {
|
||||
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("next!", t_next, Immutable, vis.clone(), Some("next"));
|
||||
self.register_py_builtin("open!", t_open, Some("open"), 198);
|
||||
let name = if cfg!(feature = "py_compat") {
|
||||
"if"
|
||||
} else {
|
||||
"if__"
|
||||
};
|
||||
let name = if PYTHON_MODE { "if" } else { "if__" };
|
||||
self.register_builtin_py_impl("if!", t_if, Immutable, vis.clone(), Some(name));
|
||||
let name = if cfg!(feature = "py_compat") {
|
||||
"for"
|
||||
} else {
|
||||
"for__"
|
||||
};
|
||||
let name = if PYTHON_MODE { "for" } else { "for__" };
|
||||
self.register_builtin_py_impl("for!", t_for, Immutable, vis.clone(), Some(name));
|
||||
let name = if cfg!(feature = "py_compat") {
|
||||
"while"
|
||||
} else {
|
||||
"while__"
|
||||
};
|
||||
let name = if PYTHON_MODE { "while" } else { "while__" };
|
||||
self.register_builtin_py_impl("while!", t_while, Immutable, vis.clone(), Some(name));
|
||||
let name = if cfg!(feature = "py_compat") {
|
||||
"with"
|
||||
} else {
|
||||
"with__"
|
||||
};
|
||||
let name = if PYTHON_MODE { "with" } else { "with__" };
|
||||
self.register_builtin_py_impl("with!", t_with, Immutable, vis, Some(name));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ impl Context {
|
|||
// 型境界はすべて各サブルーチンで定義する
|
||||
// push_subtype_boundなどはユーザー定義APIの型境界決定のために使用する
|
||||
pub(super) fn init_builtin_traits(&mut self) {
|
||||
let vis = if cfg!(feature = "py_compat") {
|
||||
let vis = if PYTHON_MODE {
|
||||
Visibility::BUILTIN_PUBLIC
|
||||
} else {
|
||||
Visibility::BUILTIN_PRIVATE
|
||||
|
|
|
@ -3,6 +3,7 @@ use std::option::Option; // conflicting to Type::Option
|
|||
use std::path::{Path, PathBuf};
|
||||
|
||||
use erg_common::config::{ErgConfig, Input};
|
||||
use erg_common::consts::{ERG_MODE, PYTHON_MODE};
|
||||
use erg_common::dict;
|
||||
use erg_common::env::{erg_py_external_lib_path, erg_pystd_path, erg_std_path};
|
||||
use erg_common::error::{ErrorCore, Location, SubMessage};
|
||||
|
@ -523,7 +524,7 @@ impl Context {
|
|||
) -> Triple<VarInfo, TyCheckError> {
|
||||
// get_attr_info(?T, aaa) == None
|
||||
// => ?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));
|
||||
if let Some(fv) = obj.ref_t().as_free() {
|
||||
if fv.get_sub().is_some() {
|
||||
|
@ -624,7 +625,7 @@ impl Context {
|
|||
}
|
||||
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);
|
||||
}
|
||||
_ => {}
|
||||
|
@ -863,7 +864,7 @@ impl Context {
|
|||
) -> SingleTyCheckResult<VarInfo> {
|
||||
// search_method_info(?T, aaa, pos_args: [1, 2]) == None
|
||||
// => ?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
|
||||
.iter()
|
||||
.map(|_| ParamTy::Pos(free_var(self.level, Constraint::new_type_of(Type))))
|
||||
|
@ -2497,9 +2498,15 @@ impl Context {
|
|||
|
||||
// FIXME: 現在の実装だとimportしたモジュールはどこからでも見れる
|
||||
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)?;
|
||||
self.get_mod_from_t(t)
|
||||
}
|
||||
}
|
||||
|
||||
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)?)
|
||||
|
@ -2571,6 +2578,11 @@ impl 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 namespace = namespaces.first().map(|n| n.to_string())?;
|
||||
namespaces.remove(0);
|
||||
|
|
|
@ -9,6 +9,7 @@ use erg_common::log;
|
|||
use erg_common::set::Set;
|
||||
use erg_common::traits::Locational;
|
||||
use erg_common::Str;
|
||||
use erg_parser::ast::VarName;
|
||||
|
||||
use crate::feature_error;
|
||||
use crate::ty::constructors::*;
|
||||
|
@ -34,8 +35,8 @@ use crate::hir;
|
|||
pub struct TyVarCache {
|
||||
_level: usize,
|
||||
pub(crate) already_appeared: Set<Str>,
|
||||
pub(crate) tyvar_instances: Dict<Str, Type>,
|
||||
pub(crate) typaram_instances: Dict<Str, TyParam>,
|
||||
pub(crate) tyvar_instances: Dict<VarName, Type>,
|
||||
pub(crate) typaram_instances: Dict<VarName, TyParam>,
|
||||
pub(crate) structural_inner: bool,
|
||||
}
|
||||
|
||||
|
@ -133,7 +134,7 @@ impl TyVarCache {
|
|||
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) {
|
||||
self.update_tyvar(inst, tv, ctx);
|
||||
} 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:
|
||||
if let Some(inst) = self.typaram_instances.get(name) {
|
||||
self.update_typaram(inst, tp, ctx);
|
||||
|
@ -262,10 +263,11 @@ impl Context {
|
|||
}
|
||||
Ok(TyParam::t(t))
|
||||
} else {
|
||||
let varname = VarName::from_str(name.clone());
|
||||
if tmp_tv_cache.appeared(&name) {
|
||||
let tp =
|
||||
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);
|
||||
}
|
||||
if let Some(tv_cache) = &self.tv_cache {
|
||||
|
@ -278,7 +280,7 @@ impl Context {
|
|||
tmp_tv_cache.push_appeared(name.clone());
|
||||
let constr = tmp_tv_cache.instantiate_constraint(constr, self, loc)?;
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -411,9 +413,10 @@ impl Context {
|
|||
)
|
||||
}
|
||||
} else {
|
||||
let varname = VarName::from_str(name.clone());
|
||||
if tmp_tv_cache.appeared(&name) {
|
||||
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);
|
||||
}
|
||||
if let Some(tv_ctx) = &self.tv_cache {
|
||||
|
@ -434,7 +437,7 @@ impl Context {
|
|||
tmp_tv_cache.push_appeared(name.clone());
|
||||
let constr = tmp_tv_cache.instantiate_constraint(constr, self, loc)?;
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ use ast::{
|
|||
NonDefaultParamSignature, ParamTySpec, PolyTypeSpec, PreDeclTypeSpec, TypeBoundSpec,
|
||||
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::Parser;
|
||||
|
||||
|
@ -124,7 +124,7 @@ impl Context {
|
|||
// TODO: other than type `Type`
|
||||
let constr = Constraint::new_type_of(Type);
|
||||
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(())
|
||||
}
|
||||
TypeBoundSpec::NonDefault { lhs, spec } => {
|
||||
|
@ -146,10 +146,10 @@ impl Context {
|
|||
};
|
||||
if constr.get_sub_sup().is_none() {
|
||||
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 {
|
||||
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(())
|
||||
}
|
||||
|
@ -536,7 +536,7 @@ impl Context {
|
|||
Ok(typ.clone())
|
||||
} else if not_found_is_qvar {
|
||||
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)
|
||||
} else {
|
||||
Err(TyCheckErrors::from(TyCheckError::no_type_error(
|
||||
|
@ -559,7 +559,7 @@ impl Context {
|
|||
tmp_tv_cache: &mut TyVarCache,
|
||||
not_found_is_qvar: bool,
|
||||
) -> TyCheckResult<Type> {
|
||||
match &poly_spec.ident.inspect()[..] {
|
||||
match poly_spec.acc.to_string().trim_start_matches("::") {
|
||||
"Array" => {
|
||||
// TODO: kw
|
||||
let mut args = poly_spec.args.pos_args();
|
||||
|
@ -647,13 +647,11 @@ impl Context {
|
|||
Ok(t.structuralize())
|
||||
}
|
||||
other => {
|
||||
let ctx = if let Some((_, ctx)) = self.get_type(&Str::rc(other)) {
|
||||
ctx
|
||||
} else {
|
||||
let Some((typ, ctx)) = self.get_type(&Str::rc(other)) else {
|
||||
return Err(TyCheckErrors::from(TyCheckError::no_type_error(
|
||||
self.cfg.input.clone(),
|
||||
line!() as usize,
|
||||
poly_spec.ident.loc(),
|
||||
poly_spec.acc.loc(),
|
||||
self.caused_by(),
|
||||
other,
|
||||
self.get_similar_name(other),
|
||||
|
@ -680,7 +678,8 @@ impl Context {
|
|||
self.level,
|
||||
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)
|
||||
} else {
|
||||
Err(e)
|
||||
|
@ -711,7 +710,7 @@ impl Context {
|
|||
}
|
||||
}
|
||||
// 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,
|
||||
not_found_is_qvar: bool,
|
||||
) -> TyCheckResult<TyParam> {
|
||||
self.inc_ref_acc(&acc.clone().downcast(), self);
|
||||
match acc {
|
||||
ast::ConstAccessor::Attr(attr) => {
|
||||
let obj = self.instantiate_const_expr(
|
||||
|
@ -734,14 +734,7 @@ impl Context {
|
|||
Ok(obj.proj(attr.name.inspect()))
|
||||
}
|
||||
ast::ConstAccessor::Local(local) => {
|
||||
self.inc_ref_local(local, self);
|
||||
self.instantiate_local(
|
||||
local.inspect(),
|
||||
erased_idx,
|
||||
tmp_tv_cache,
|
||||
local,
|
||||
not_found_is_qvar,
|
||||
)
|
||||
self.instantiate_local(local, erased_idx, tmp_tv_cache, local, not_found_is_qvar)
|
||||
}
|
||||
other => type_feature_error!(
|
||||
self,
|
||||
|
@ -753,13 +746,13 @@ impl Context {
|
|||
|
||||
fn instantiate_local(
|
||||
&self,
|
||||
name: &Str,
|
||||
name: &Identifier,
|
||||
erased_idx: Option<(&Context, usize)>,
|
||||
tmp_tv_cache: &mut TyVarCache,
|
||||
loc: &impl Locational,
|
||||
not_found_is_qvar: bool,
|
||||
) -> TyCheckResult<TyParam> {
|
||||
if &name[..] == "_" {
|
||||
if &name.inspect()[..] == "_" {
|
||||
let t = if let Some((ctx, i)) = erased_idx {
|
||||
let param = ctx.params.get(i).ok_or_else(|| {
|
||||
TyCheckErrors::from(TyCheckError::too_many_args_error(
|
||||
|
@ -779,15 +772,15 @@ impl Context {
|
|||
};
|
||||
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);
|
||||
}
|
||||
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()));
|
||||
}
|
||||
if not_found_is_qvar {
|
||||
let tyvar = named_free_var(name.clone(), self.level, Constraint::Uninited);
|
||||
tmp_tv_cache.push_or_init_tyvar(name, &tyvar, self);
|
||||
let tyvar = named_free_var(name.inspect().clone(), self.level, Constraint::Uninited);
|
||||
tmp_tv_cache.push_or_init_tyvar(&name.name, &tyvar, self);
|
||||
return Ok(TyParam::t(tyvar));
|
||||
}
|
||||
Err(TyCheckErrors::from(TyCheckError::no_var_error(
|
||||
|
@ -795,8 +788,8 @@ impl Context {
|
|||
line!() as usize,
|
||||
loc.loc(),
|
||||
self.caused_by(),
|
||||
name,
|
||||
self.get_similar_name(name),
|
||||
name.inspect(),
|
||||
self.get_similar_name(name.inspect()),
|
||||
)))
|
||||
}
|
||||
|
||||
|
@ -814,7 +807,6 @@ impl Context {
|
|||
}
|
||||
match expr {
|
||||
ast::ConstExpr::Lit(lit) => Ok(TyParam::Value(self.eval_lit(lit)?)),
|
||||
// TODO: inc_ref
|
||||
ast::ConstExpr::Accessor(acc) => {
|
||||
self.instantiate_acc(acc, erased_idx, tmp_tv_cache, not_found_is_qvar)
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ use std::option::Option; // conflicting to Type::Option
|
|||
use std::path::{Path, PathBuf};
|
||||
|
||||
use erg_common::config::ErgConfig;
|
||||
use erg_common::consts::PYTHON_MODE;
|
||||
use erg_common::dict::Dict;
|
||||
use erg_common::error::Location;
|
||||
use erg_common::impl_display_from_debug;
|
||||
|
@ -68,7 +69,7 @@ impl TryFrom<&str> for ControlKind {
|
|||
match s {
|
||||
"if" | "if!" => Ok(ControlKind::If),
|
||||
"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),
|
||||
"match" | "match!" => Ok(ControlKind::Match),
|
||||
"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.
|
||||
/// `.cfg` is not initialized and is used around.
|
||||
pub fn initialize(&mut self) {
|
||||
|
@ -1016,6 +1029,9 @@ impl Context {
|
|||
};
|
||||
log!(info "{}: current namespace: {name}", fn_name!());
|
||||
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.shared = self.get_outer().unwrap().shared.clone();
|
||||
self.tv_cache = tv_cache;
|
||||
|
|
|
@ -6,6 +6,7 @@ use std::process::{Command, Stdio};
|
|||
use std::time::SystemTime;
|
||||
|
||||
use erg_common::config::ErgMode;
|
||||
use erg_common::consts::PYTHON_MODE;
|
||||
use erg_common::env::erg_pystd_path;
|
||||
use erg_common::erg_util::BUILTIN_ERG_MODS;
|
||||
use erg_common::levenshtein::get_similar_name;
|
||||
|
@ -16,8 +17,11 @@ use erg_common::triple::Triple;
|
|||
use erg_common::Str;
|
||||
use erg_common::{get_hash, log, set};
|
||||
|
||||
use ast::{ConstIdentifier, Decorator, DefId, Identifier, OperationKind, PolyTypeSpec, VarName};
|
||||
use erg_parser::ast::{self, PreDeclTypeSpec};
|
||||
use ast::{
|
||||
ConstIdentifier, Decorator, DefId, Identifier, OperationKind, PolyTypeSpec, PreDeclTypeSpec,
|
||||
VarName,
|
||||
};
|
||||
use erg_parser::ast;
|
||||
|
||||
use crate::ty::constructors::{
|
||||
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
|
||||
.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();
|
||||
symbol.content = py_name.clone().unwrap();
|
||||
Identifier::new(ident.vis.clone(), VarName::new(symbol))
|
||||
|
@ -344,7 +348,7 @@ impl Context {
|
|||
opt_decl_t: Option<&ParamTy>,
|
||||
kind: ParamKind,
|
||||
) -> TyCheckResult<()> {
|
||||
let vis = if cfg!(feature = "py_compat") {
|
||||
let vis = if PYTHON_MODE {
|
||||
Visibility::BUILTIN_PUBLIC
|
||||
} else {
|
||||
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(
|
||||
&mut self,
|
||||
params: &mut hir::Params,
|
||||
|
@ -2003,48 +2020,53 @@ impl Context {
|
|||
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 {
|
||||
ast::Accessor::Ident(ident) => self.inc_ref_local(ident, namespace),
|
||||
ast::Accessor::Attr(attr) => {
|
||||
self.inc_ref_expr(&attr.obj, namespace);
|
||||
if let Ok(ctxs) = self.get_singular_ctxs(&attr.obj, self) {
|
||||
if let Some(first) = ctxs.first() {
|
||||
first.inc_ref_local(&attr.ident, namespace);
|
||||
for ctx in ctxs {
|
||||
if ctx.inc_ref_local(&attr.ident, namespace) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
false
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn inc_ref_expr(&self, expr: &ast::Expr, namespace: &Context) {
|
||||
#[allow(clippy::single_match)]
|
||||
match expr {
|
||||
ast::Expr::Accessor(acc) => self.inc_ref_acc(acc, namespace),
|
||||
// TODO:
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn inc_ref_predecl_typespec(&self, predecl: &PreDeclTypeSpec, namespace: &Context) {
|
||||
pub(crate) fn inc_ref_predecl_typespec(
|
||||
&self,
|
||||
predecl: &PreDeclTypeSpec,
|
||||
namespace: &Context,
|
||||
) -> bool {
|
||||
match predecl {
|
||||
PreDeclTypeSpec::Mono(mono) => self.inc_ref_mono_typespec(mono, namespace),
|
||||
PreDeclTypeSpec::Poly(poly) => self.inc_ref_poly_typespec(poly, namespace),
|
||||
PreDeclTypeSpec::Attr { namespace: obj, t } => {
|
||||
self.inc_ref_expr(obj, namespace);
|
||||
if let Ok(ctxs) = self.get_singular_ctxs(obj, self) {
|
||||
if let Some(first) = ctxs.first() {
|
||||
first.inc_ref_mono_typespec(t, namespace);
|
||||
for ctx in ctxs {
|
||||
if ctx.inc_ref_mono_typespec(t, namespace) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
// 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(
|
||||
ident,
|
||||
crate::compile::AccessKind::Name,
|
||||
|
@ -2052,22 +2074,18 @@ impl Context {
|
|||
self,
|
||||
) {
|
||||
self.inc_ref(&vi, &ident.name, namespace);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// TODO:
|
||||
pub(crate) fn inc_ref_poly_typespec(&self, poly: &PolyTypeSpec, namespace: &Context) {
|
||||
if let Triple::Ok(vi) = self.rec_get_var_info(
|
||||
&poly.ident,
|
||||
crate::compile::AccessKind::Name,
|
||||
&self.cfg.input,
|
||||
self,
|
||||
) {
|
||||
self.inc_ref(&vi, &poly.ident.name, namespace);
|
||||
}
|
||||
/// TODO: params
|
||||
fn inc_ref_poly_typespec(&self, poly: &PolyTypeSpec, namespace: &Context) -> bool {
|
||||
self.inc_ref_acc(&poly.acc.clone().downcast(), 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(
|
||||
local,
|
||||
crate::compile::AccessKind::Name,
|
||||
|
@ -2075,10 +2093,18 @@ impl Context {
|
|||
self,
|
||||
) {
|
||||
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) {
|
||||
self.index().inc_ref(vi, namespace.absolutize(name.loc()));
|
||||
fn inc_ref_expr(&self, expr: &ast::Expr, namespace: &Context) -> bool {
|
||||
#[allow(clippy::single_match)]
|
||||
match expr {
|
||||
ast::Expr::Accessor(acc) => self.inc_ref_acc(acc, namespace),
|
||||
// TODO:
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use erg_common::consts::PYTHON_MODE;
|
||||
use erg_common::traits::{Locational, Runnable, Stream};
|
||||
use erg_common::{enum_unwrap, fn_name, log, set, Str};
|
||||
|
||||
|
@ -562,7 +563,7 @@ impl ASTLowerer {
|
|||
Some(py_name.clone()),
|
||||
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();
|
||||
symbol.content = py_name.clone();
|
||||
VarName::new(symbol)
|
||||
|
@ -571,7 +572,7 @@ impl ASTLowerer {
|
|||
};
|
||||
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();
|
||||
symbol.content = py_name.clone();
|
||||
Identifier::new(ident.vis.clone(), VarName::new(symbol))
|
||||
|
@ -610,7 +611,7 @@ impl ASTLowerer {
|
|||
if ident.is_raw() {
|
||||
return Ok(());
|
||||
}
|
||||
let name = if cfg!(feature = "py_compat") {
|
||||
let name = if PYTHON_MODE {
|
||||
self.module
|
||||
.context
|
||||
.erg_to_py_names
|
||||
|
|
|
@ -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(
|
||||
input: Input,
|
||||
errno: usize,
|
||||
|
|
|
@ -4,17 +4,27 @@
|
|||
.Hashable: ClassType
|
||||
.Sized: ClassType
|
||||
.Callable: ClassType
|
||||
.Callable.
|
||||
__getitem__: (params: [Type; _], Type) -> Type
|
||||
.Iterable: ClassType
|
||||
.Iterable.
|
||||
__getitem__: Type -> Type
|
||||
.Collection: ClassType
|
||||
.Iterator: ClassType
|
||||
.Iterator.
|
||||
__getitem__: Type -> Type
|
||||
.Reversible: ClassType
|
||||
.Genertor: ClassType
|
||||
.Sequence: ClassType
|
||||
.Sequence.
|
||||
__getitem__: Type -> Type
|
||||
.MutableSqunce: ClassType
|
||||
.ByteString: ClassType
|
||||
.Set: ClassType
|
||||
.MutableSet: ClassType
|
||||
.Mapping: ClassType
|
||||
.Mapping.
|
||||
__getitem__: (Type, Type) -> Type
|
||||
.MutableMapping: ClassType
|
||||
.MappingView: ClassType
|
||||
.ItemsView: ClassType
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
use std::mem;
|
||||
|
||||
use erg_common::config::{ErgConfig, ErgMode};
|
||||
use erg_common::consts::{ERG_MODE, PYTHON_MODE};
|
||||
use erg_common::dict;
|
||||
use erg_common::dict::Dict;
|
||||
use erg_common::error::{Location, MultiErrorDisplay};
|
||||
|
@ -280,7 +281,7 @@ impl ASTLowerer {
|
|||
(false, false) => {
|
||||
if let hir::Expr::TypeAsc(type_asc) = &elem {
|
||||
// e.g. [1, "a": Str or NoneType]
|
||||
if !cfg!(feature = "py_compat")
|
||||
if ERG_MODE
|
||||
&& !self
|
||||
.module
|
||||
.context
|
||||
|
@ -288,7 +289,7 @@ impl ASTLowerer {
|
|||
{
|
||||
return Err(self.elem_err(&l, &r, &elem));
|
||||
} // 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));
|
||||
}
|
||||
}
|
||||
|
@ -399,7 +400,7 @@ impl ASTLowerer {
|
|||
for elem in elems {
|
||||
let elem = self.lower_expr(elem.expr)?;
|
||||
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(
|
||||
self.cfg.input.clone(),
|
||||
line!() as usize,
|
||||
|
@ -515,7 +516,7 @@ impl ASTLowerer {
|
|||
let key = self.lower_expr(kv.key)?;
|
||||
let value = self.lower_expr(kv.value)?;
|
||||
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();
|
||||
*val_t = self.module.context.union(&mem::take(val_t), &popped_val_t);
|
||||
} else {
|
||||
|
@ -1146,7 +1147,7 @@ impl ASTLowerer {
|
|||
|
||||
fn lower_lambda(&mut self, lambda: ast::Lambda) -> LowerResult<hir::Lambda> {
|
||||
log!(info "entered {}({lambda})", fn_name!());
|
||||
let in_statement = cfg!(feature = "py_compat")
|
||||
let in_statement = PYTHON_MODE
|
||||
&& self
|
||||
.module
|
||||
.context
|
||||
|
@ -1335,7 +1336,17 @@ impl ASTLowerer {
|
|||
} else {
|
||||
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
|
||||
.context
|
||||
.registered_info(&name, def.sig.is_const())
|
||||
|
|
|
@ -1437,15 +1437,14 @@ impl ConstSubscript {
|
|||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum ConstAccessor {
|
||||
Local(ConstIdentifier),
|
||||
SelfDot(ConstIdentifier),
|
||||
Attr(ConstAttribute),
|
||||
TupleAttr(ConstTupleAttribute),
|
||||
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_locational_for_enum!(ConstAccessor; Local, SelfDot, Attr, TupleAttr, Subscr);
|
||||
impl_locational_for_enum!(ConstAccessor; Local, Attr, TupleAttr, Subscr);
|
||||
|
||||
impl ConstAccessor {
|
||||
pub const fn local(symbol: Token) -> Self {
|
||||
|
@ -2165,31 +2164,31 @@ impl ConstArgs {
|
|||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct PolyTypeSpec {
|
||||
pub ident: Identifier,
|
||||
pub acc: ConstAccessor,
|
||||
pub args: ConstArgs, // args can be nested (e.g. Vec Vec Int)
|
||||
}
|
||||
|
||||
impl fmt::Display for PolyTypeSpec {
|
||||
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 {
|
||||
fn loc(&self) -> Location {
|
||||
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() {
|
||||
Location::concat(&self.ident, last)
|
||||
Location::concat(&self.acc, last)
|
||||
} else {
|
||||
self.ident.loc()
|
||||
self.acc.loc()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PolyTypeSpec {
|
||||
pub const fn new(ident: Identifier, args: ConstArgs) -> Self {
|
||||
Self { ident, args }
|
||||
pub const fn new(acc: ConstAccessor, args: ConstArgs) -> Self {
|
||||
Self { acc, args }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2253,6 +2252,10 @@ impl PreDeclTypeSpec {
|
|||
t,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn poly(acc: ConstAccessor, args: ConstArgs) -> Self {
|
||||
Self::Poly(PolyTypeSpec::new(acc, args))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
|
@ -2586,8 +2589,8 @@ impl TypeSpec {
|
|||
Self::PreDeclTy(PreDeclTypeSpec::Mono(ident))
|
||||
}
|
||||
|
||||
pub fn poly(ident: Identifier, args: ConstArgs) -> Self {
|
||||
Self::PreDeclTy(PreDeclTypeSpec::Poly(PolyTypeSpec::new(ident, args)))
|
||||
pub fn poly(acc: ConstAccessor, args: ConstArgs) -> Self {
|
||||
Self::PreDeclTy(PreDeclTypeSpec::Poly(PolyTypeSpec::new(acc, args)))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2632,11 +2635,11 @@ impl TypeSpecWithOp {
|
|||
pub enum TypeBoundSpec {
|
||||
Omitted(VarName),
|
||||
NonDefault {
|
||||
lhs: Token,
|
||||
lhs: VarName,
|
||||
spec: TypeSpecWithOp,
|
||||
},
|
||||
WithDefault {
|
||||
lhs: Token,
|
||||
lhs: VarName,
|
||||
spec: Box<TypeSpecWithOp>,
|
||||
default: ConstExpr,
|
||||
}, // 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 {
|
||||
match self {
|
||||
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 } => {
|
||||
write!(f, "{}{} := {}", lhs.content, spec, default)
|
||||
write!(f, "{lhs} {spec} := {default}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2667,9 +2670,17 @@ impl Locational for 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 }
|
||||
}
|
||||
|
||||
pub fn default(lhs: VarName, spec: TypeSpecWithOp, default: ConstExpr) -> Self {
|
||||
Self::WithDefault {
|
||||
lhs,
|
||||
spec: Box::new(spec),
|
||||
default,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
|
|
|
@ -348,7 +348,7 @@ impl Parser {
|
|||
self.errs.push(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)
|
||||
}
|
||||
Expr::Accessor(Accessor::Ident(ident)) => {
|
||||
|
|
|
@ -1887,11 +1887,7 @@ impl Parser {
|
|||
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) {
|
||||
let args = res.map_err(|_| self.stack_dec(fn_name!()))?;
|
||||
let (receiver, attr_name) = match call_or_acc {
|
||||
Expr::Accessor(Accessor::Attr(attr)) => (*attr.obj, Some(attr.ident)),
|
||||
other => (other, None),
|
||||
};
|
||||
let call = Call::new(receiver, attr_name, args);
|
||||
let call = call_or_acc.call(args);
|
||||
call_or_acc = Expr::Call(call);
|
||||
}
|
||||
debug_exit_info!(self);
|
||||
|
|
|
@ -221,10 +221,15 @@ impl Parser {
|
|||
let const_expr = Self::validate_const_expr(arg.expr)?;
|
||||
kw_args.push(ConstKwArg::new(arg.keyword, const_expr));
|
||||
}
|
||||
Ok(PreDeclTypeSpec::Poly(PolyTypeSpec::new(
|
||||
ident,
|
||||
let acc = if let Some(attr) = call.attr_name {
|
||||
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),
|
||||
)))
|
||||
))
|
||||
}
|
||||
other => {
|
||||
let err = ParseError::simple_syntax_error(line!() as usize, other.loc());
|
||||
|
|
|
@ -62,6 +62,40 @@ if x.is_zero(), do:
|
|||
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 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.
|
||||
|
|
|
@ -68,6 +68,40 @@ if x.is_zero(), do:
|
|||
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
|
||||
```
|
||||
|
||||
## 定数
|
||||
|
||||
定数も代数の一種です。識別子を大文字で始めると定数として扱われます。一度定義したら変わらないので、定数と呼ばれます。
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue