mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-30 04:44:44 +00:00
Implement Patch
This commit is contained in:
parent
7078f95cec
commit
bade70ef91
22 changed files with 741 additions and 116 deletions
|
@ -40,7 +40,7 @@ use crate::context::eval::type_from_token_kind;
|
||||||
use crate::error::CompileError;
|
use crate::error::CompileError;
|
||||||
use crate::hir::{
|
use crate::hir::{
|
||||||
Accessor, Args, Array, AttrDef, BinOp, Block, Call, ClassDef, Def, DefBody, Expr, Identifier,
|
Accessor, Args, Array, AttrDef, BinOp, Block, Call, ClassDef, Def, DefBody, Expr, Identifier,
|
||||||
Lambda, Literal, Params, PosArg, Record, Signature, SubrSignature, Tuple, UnaryOp,
|
Lambda, Literal, Params, PatchDef, PosArg, Record, Signature, SubrSignature, Tuple, UnaryOp,
|
||||||
VarSignature, HIR,
|
VarSignature, HIR,
|
||||||
};
|
};
|
||||||
use crate::ty::value::ValueObj;
|
use crate::ty::value::ValueObj;
|
||||||
|
@ -48,11 +48,16 @@ use crate::ty::{HasType, Type, TypeCode, TypePair};
|
||||||
use erg_common::fresh::fresh_varname;
|
use erg_common::fresh::fresh_varname;
|
||||||
use AccessKind::*;
|
use AccessKind::*;
|
||||||
|
|
||||||
fn fake_method_to_func(class: &str, name: &str) -> Option<&'static str> {
|
/// patch method -> function
|
||||||
match (class, name) {
|
/// patch attr -> variable
|
||||||
(_, "abs") => Some("abs"),
|
fn debind(name: Option<&str>) -> Option<Str> {
|
||||||
(_, "iter") => Some("iter"),
|
match name {
|
||||||
(_, "map") => Some("map"),
|
Some(name) if name.starts_with("Function::") => {
|
||||||
|
Some(Str::from(name.replace("Function::", "")))
|
||||||
|
}
|
||||||
|
Some(patch_method) if patch_method.contains("::") || patch_method.contains('.') => {
|
||||||
|
Some(Str::rc(patch_method))
|
||||||
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -873,8 +878,14 @@ impl PyCodeGenerator {
|
||||||
if is_record {
|
if is_record {
|
||||||
a.ident.dot = Some(DOT);
|
a.ident.dot = Some(DOT);
|
||||||
}
|
}
|
||||||
self.emit_expr(*a.obj);
|
if let Some(varname) = debind(a.ident.vi.py_name.as_ref().map(|s| &s[..])) {
|
||||||
self.emit_load_attr_instr(a.ident);
|
a.ident.dot = None;
|
||||||
|
a.ident.name = VarName::from_str(varname);
|
||||||
|
self.emit_load_name_instr(a.ident);
|
||||||
|
} else {
|
||||||
|
self.emit_expr(*a.obj);
|
||||||
|
self.emit_load_attr_instr(a.ident);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1135,6 +1146,27 @@ impl PyCodeGenerator {
|
||||||
self.stack_dec();
|
self.stack_dec();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn emit_patch_def(&mut self, patch_def: PatchDef) {
|
||||||
|
log!(info "entered {} ({})", fn_name!(), patch_def.sig);
|
||||||
|
for def in patch_def.methods {
|
||||||
|
// Invert.
|
||||||
|
// invert self = ...
|
||||||
|
// ↓
|
||||||
|
// def Invert::invert(self): ...
|
||||||
|
let Expr::Def(mut def) = def else { todo!() };
|
||||||
|
let namespace = self.cur_block_codeobj().name.trim_start_matches("::");
|
||||||
|
let name = format!(
|
||||||
|
"{}{}{}",
|
||||||
|
namespace,
|
||||||
|
patch_def.sig.ident().to_string_without_type(),
|
||||||
|
def.sig.ident().to_string_without_type()
|
||||||
|
);
|
||||||
|
def.sig.ident_mut().name = VarName::from_str(Str::from(name));
|
||||||
|
def.sig.ident_mut().dot = None;
|
||||||
|
self.emit_def(def);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE: use `TypeVar`, `Generic` in `typing` module
|
// NOTE: use `TypeVar`, `Generic` in `typing` module
|
||||||
// fn emit_poly_type_def(&mut self, sig: SubrSignature, body: DefBody) {}
|
// fn emit_poly_type_def(&mut self, sig: SubrSignature, body: DefBody) {}
|
||||||
|
|
||||||
|
@ -1986,14 +2018,13 @@ impl PyCodeGenerator {
|
||||||
|
|
||||||
fn emit_call_method(&mut self, obj: Expr, method_name: Identifier, args: Args) {
|
fn emit_call_method(&mut self, obj: Expr, method_name: Identifier, args: Args) {
|
||||||
log!(info "entered {}", fn_name!());
|
log!(info "entered {}", fn_name!());
|
||||||
let class = obj.ref_t().qual_name(); // これは必ずmethodのあるクラスになっている
|
|
||||||
if &method_name.inspect()[..] == "update!" {
|
if &method_name.inspect()[..] == "update!" {
|
||||||
if self.py_version.minor >= Some(11) {
|
if self.py_version.minor >= Some(11) {
|
||||||
return self.emit_call_update_311(obj, args);
|
return self.emit_call_update_311(obj, args);
|
||||||
} else {
|
} else {
|
||||||
return self.emit_call_update_310(obj, args);
|
return self.emit_call_update_310(obj, args);
|
||||||
}
|
}
|
||||||
} else if let Some(func_name) = fake_method_to_func(&class, method_name.inspect()) {
|
} else if let Some(func_name) = debind(method_name.vi.py_name.as_ref().map(|s| &s[..])) {
|
||||||
return self.emit_call_fake_method(obj, func_name, method_name, args);
|
return self.emit_call_fake_method(obj, func_name, method_name, args);
|
||||||
}
|
}
|
||||||
let is_py_api = obj.is_py_api();
|
let is_py_api = obj.is_py_api();
|
||||||
|
@ -2114,13 +2145,13 @@ impl PyCodeGenerator {
|
||||||
fn emit_call_fake_method(
|
fn emit_call_fake_method(
|
||||||
&mut self,
|
&mut self,
|
||||||
obj: Expr,
|
obj: Expr,
|
||||||
func_name: &'static str,
|
func_name: Str,
|
||||||
mut method_name: Identifier,
|
mut method_name: Identifier,
|
||||||
mut args: Args,
|
mut args: Args,
|
||||||
) {
|
) {
|
||||||
log!(info "entered {}", fn_name!());
|
log!(info "entered {}", fn_name!());
|
||||||
method_name.dot = None;
|
method_name.dot = None;
|
||||||
method_name.vi.py_name = Some(Str::ever(func_name));
|
method_name.vi.py_name = Some(func_name);
|
||||||
self.emit_push_null();
|
self.emit_push_null();
|
||||||
self.emit_load_name_instr(method_name);
|
self.emit_load_name_instr(method_name);
|
||||||
args.insert_pos(0, PosArg::new(obj));
|
args.insert_pos(0, PosArg::new(obj));
|
||||||
|
@ -2314,6 +2345,7 @@ impl PyCodeGenerator {
|
||||||
Expr::Accessor(acc) => self.emit_acc(acc),
|
Expr::Accessor(acc) => self.emit_acc(acc),
|
||||||
Expr::Def(def) => self.emit_def(def),
|
Expr::Def(def) => self.emit_def(def),
|
||||||
Expr::ClassDef(class) => self.emit_class_def(class),
|
Expr::ClassDef(class) => self.emit_class_def(class),
|
||||||
|
Expr::PatchDef(patch) => self.emit_patch_def(patch),
|
||||||
Expr::AttrDef(attr) => self.emit_attr_def(attr),
|
Expr::AttrDef(attr) => self.emit_attr_def(attr),
|
||||||
Expr::Lambda(lambda) => self.emit_lambda(lambda),
|
Expr::Lambda(lambda) => self.emit_lambda(lambda),
|
||||||
Expr::UnaryOp(unary) => self.emit_unaryop(unary),
|
Expr::UnaryOp(unary) => self.emit_unaryop(unary),
|
||||||
|
|
|
@ -245,8 +245,20 @@ impl Context {
|
||||||
self.nominal_supertype_of(rhs, lhs)
|
self.nominal_supertype_of(rhs, lhs)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _find_compatible_patch(&self, sup: &Type, sub: &Type) -> Option<&Context> {
|
pub(crate) fn find_patches_of<'a>(
|
||||||
for patch in self._all_patches().into_iter() {
|
&'a self,
|
||||||
|
typ: &'a Type,
|
||||||
|
) -> impl Iterator<Item = &'a Context> {
|
||||||
|
self.all_patches().into_iter().filter(|ctx| {
|
||||||
|
if let ContextKind::Patch(base) = &ctx.kind {
|
||||||
|
return self.supertype_of(base, typ);
|
||||||
|
}
|
||||||
|
false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _find_compatible_glue_patch(&self, sup: &Type, sub: &Type) -> Option<&Context> {
|
||||||
|
for patch in self.all_patches().into_iter() {
|
||||||
if let ContextKind::GluePatch(tr_inst) = &patch.kind {
|
if let ContextKind::GluePatch(tr_inst) = &patch.kind {
|
||||||
if self.subtype_of(sub, &tr_inst.sub_type)
|
if self.subtype_of(sub, &tr_inst.sub_type)
|
||||||
&& self.subtype_of(&tr_inst.sup_trait, sup)
|
&& self.subtype_of(&tr_inst.sup_trait, sup)
|
||||||
|
|
|
@ -246,7 +246,12 @@ impl Context {
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
todo!()
|
Err(EvalErrors::from(EvalError::not_const_expr(
|
||||||
|
self.cfg.input.clone(),
|
||||||
|
line!() as usize,
|
||||||
|
call.loc(),
|
||||||
|
self.caused_by(),
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,12 +316,15 @@ impl Context {
|
||||||
let elem = self.eval_const_expr(&elem.expr)?;
|
let elem = self.eval_const_expr(&elem.expr)?;
|
||||||
elems.push(elem);
|
elems.push(elem);
|
||||||
}
|
}
|
||||||
|
Ok(ValueObj::Array(RcArray::from(elems)))
|
||||||
}
|
}
|
||||||
_ => {
|
_ => Err(EvalErrors::from(EvalError::not_const_expr(
|
||||||
todo!()
|
self.cfg.input.clone(),
|
||||||
}
|
line!() as usize,
|
||||||
|
arr.loc(),
|
||||||
|
self.caused_by(),
|
||||||
|
))),
|
||||||
}
|
}
|
||||||
Ok(ValueObj::Array(RcArray::from(elems)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_const_set(&self, set: &AstSet) -> EvalResult<ValueObj> {
|
fn eval_const_set(&self, set: &AstSet) -> EvalResult<ValueObj> {
|
||||||
|
@ -327,12 +335,15 @@ impl Context {
|
||||||
let elem = self.eval_const_expr(&elem.expr)?;
|
let elem = self.eval_const_expr(&elem.expr)?;
|
||||||
elems.push(elem);
|
elems.push(elem);
|
||||||
}
|
}
|
||||||
|
Ok(ValueObj::Set(Set::from(elems)))
|
||||||
}
|
}
|
||||||
_ => {
|
_ => Err(EvalErrors::from(EvalError::not_const_expr(
|
||||||
todo!()
|
self.cfg.input.clone(),
|
||||||
}
|
line!() as usize,
|
||||||
|
set.loc(),
|
||||||
|
self.caused_by(),
|
||||||
|
))),
|
||||||
}
|
}
|
||||||
Ok(ValueObj::Set(Set::from(elems)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_const_dict(&self, dict: &AstDict) -> EvalResult<ValueObj> {
|
fn eval_const_dict(&self, dict: &AstDict) -> EvalResult<ValueObj> {
|
||||||
|
@ -344,12 +355,15 @@ impl Context {
|
||||||
let value = self.eval_const_expr(&elem.value)?;
|
let value = self.eval_const_expr(&elem.value)?;
|
||||||
elems.insert(key, value);
|
elems.insert(key, value);
|
||||||
}
|
}
|
||||||
|
Ok(ValueObj::Dict(elems))
|
||||||
}
|
}
|
||||||
_ => {
|
_ => Err(EvalErrors::from(EvalError::not_const_expr(
|
||||||
todo!()
|
self.cfg.input.clone(),
|
||||||
}
|
line!() as usize,
|
||||||
|
dict.loc(),
|
||||||
|
self.caused_by(),
|
||||||
|
))),
|
||||||
}
|
}
|
||||||
Ok(ValueObj::Dict(elems))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_const_tuple(&self, tuple: &Tuple) -> EvalResult<ValueObj> {
|
fn eval_const_tuple(&self, tuple: &Tuple) -> EvalResult<ValueObj> {
|
||||||
|
|
|
@ -143,6 +143,35 @@ pub fn trait_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<ValueOb
|
||||||
Ok(ValueObj::gen_t(GenTypeObj::trait_(t, require, impls)))
|
Ok(ValueObj::gen_t(GenTypeObj::trait_(t, require, impls)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Base: Type, Impl := Type -> Patch
|
||||||
|
pub fn patch_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<ValueObj> {
|
||||||
|
let base = args.remove_left_or_key("Base").ok_or_else(|| {
|
||||||
|
ErrorCore::new(
|
||||||
|
vec![SubMessage::only_loc(Location::Unknown)],
|
||||||
|
format!("{REQ_ERR} is not passed"),
|
||||||
|
line!() as usize,
|
||||||
|
ErrorKind::KeyError,
|
||||||
|
Location::Unknown,
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
let Some(base) = base.as_type() else {
|
||||||
|
let base = StyledString::new(&format!("{base}"), Some(ERR), None);
|
||||||
|
return Err(ErrorCore::new(
|
||||||
|
vec![SubMessage::only_loc(Location::Unknown)],
|
||||||
|
format!(
|
||||||
|
"non-type object {base} is passed to {REQ_WARN}",
|
||||||
|
),
|
||||||
|
line!() as usize,
|
||||||
|
ErrorKind::TypeError,
|
||||||
|
Location::Unknown,
|
||||||
|
).into());
|
||||||
|
};
|
||||||
|
let impls = args.remove_left_or_key("Impl");
|
||||||
|
let impls = impls.map(|v| v.as_type().unwrap());
|
||||||
|
let t = mono(ctx.name.clone());
|
||||||
|
Ok(ValueObj::gen_t(GenTypeObj::patch(t, base, impls)))
|
||||||
|
}
|
||||||
|
|
||||||
/// Super: TraitType, Impl := Type, Additional := Type -> TraitType
|
/// Super: TraitType, Impl := Type, Additional := Type -> TraitType
|
||||||
pub fn subsume_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<ValueObj> {
|
pub fn subsume_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<ValueObj> {
|
||||||
let sup = args.remove_left_or_key("Super").ok_or_else(|| {
|
let sup = args.remove_left_or_key("Super").ok_or_else(|| {
|
||||||
|
|
|
@ -491,7 +491,7 @@ impl Context {
|
||||||
iterable.register_superclass(poly("Output", vec![ty_tp(T.clone())]), &output);
|
iterable.register_superclass(poly("Output", vec![ty_tp(T.clone())]), &output);
|
||||||
let Slf = mono_q("Self", subtypeof(poly("Iterable", vec![ty_tp(T.clone())])));
|
let Slf = mono_q("Self", subtypeof(poly("Iterable", vec![ty_tp(T.clone())])));
|
||||||
let t = fn0_met(Slf.clone(), proj(Slf, "Iter")).quantify();
|
let t = fn0_met(Slf.clone(), proj(Slf, "Iter")).quantify();
|
||||||
iterable.register_builtin_decl("iter", t, Public);
|
iterable.register_builtin_py_decl("iter", t, Public, Some("__iter__"));
|
||||||
iterable.register_builtin_decl("Iter", Type, Public);
|
iterable.register_builtin_decl("Iter", Type, Public);
|
||||||
let R = mono_q("R", instanceof(Type));
|
let R = mono_q("R", instanceof(Type));
|
||||||
let params = vec![PS::t("R", WithDefault)];
|
let params = vec![PS::t("R", WithDefault)];
|
||||||
|
@ -772,7 +772,7 @@ impl Context {
|
||||||
int.register_marker_trait(mono("Num"));
|
int.register_marker_trait(mono("Num"));
|
||||||
// class("Rational"),
|
// class("Rational"),
|
||||||
// class("Integral"),
|
// class("Integral"),
|
||||||
int.register_builtin_impl("abs", fn0_met(Int, Nat), Immutable, Public);
|
int.register_builtin_py_impl("abs", fn0_met(Int, Nat), Immutable, Public, Some("__abs__"));
|
||||||
let mut int_ord = Self::builtin_methods(Some(mono("Ord")), 2);
|
let mut int_ord = Self::builtin_methods(Some(mono("Ord")), 2);
|
||||||
int_ord.register_builtin_impl(
|
int_ord.register_builtin_impl(
|
||||||
"__partial_cmp__",
|
"__partial_cmp__",
|
||||||
|
@ -927,6 +927,20 @@ impl Context {
|
||||||
Immutable,
|
Immutable,
|
||||||
Public,
|
Public,
|
||||||
);
|
);
|
||||||
|
str_.register_builtin_impl(
|
||||||
|
"lower",
|
||||||
|
fn_met(Str, vec![], None, vec![], Str),
|
||||||
|
Immutable,
|
||||||
|
Public,
|
||||||
|
);
|
||||||
|
str_.register_builtin_impl(
|
||||||
|
"upper",
|
||||||
|
fn_met(Str, vec![], None, vec![], Str),
|
||||||
|
Immutable,
|
||||||
|
Public,
|
||||||
|
);
|
||||||
|
let str_getitem_t = fn1_kw_met(Str, kw("idx", Nat), Str);
|
||||||
|
str_.register_builtin_impl("__getitem__", str_getitem_t, Immutable, Public);
|
||||||
let mut str_eq = Self::builtin_methods(Some(mono("Eq")), 2);
|
let mut str_eq = Self::builtin_methods(Some(mono("Eq")), 2);
|
||||||
str_eq.register_builtin_impl("__eq__", fn1_met(Str, Str, Bool), Const, Public);
|
str_eq.register_builtin_impl("__eq__", fn1_met(Str, Str, Bool), Const, Public);
|
||||||
str_.register_trait(Str, str_eq);
|
str_.register_trait(Str, str_eq);
|
||||||
|
@ -949,11 +963,12 @@ impl Context {
|
||||||
str_show.register_builtin_impl("to_str", fn0_met(Str, Str), Immutable, Public);
|
str_show.register_builtin_impl("to_str", fn0_met(Str, Str), Immutable, Public);
|
||||||
str_.register_trait(Str, str_show);
|
str_.register_trait(Str, str_show);
|
||||||
let mut str_iterable = Self::builtin_methods(Some(poly("Iterable", vec![ty_tp(Str)])), 2);
|
let mut str_iterable = Self::builtin_methods(Some(poly("Iterable", vec![ty_tp(Str)])), 2);
|
||||||
str_iterable.register_builtin_impl(
|
str_iterable.register_builtin_py_impl(
|
||||||
"iter",
|
"iter",
|
||||||
fn0_met(Str, mono("StrIterator")),
|
fn0_met(Str, mono("StrIterator")),
|
||||||
Immutable,
|
Immutable,
|
||||||
Public,
|
Public,
|
||||||
|
Some("__iter__"),
|
||||||
);
|
);
|
||||||
str_.register_trait(Str, str_iterable);
|
str_.register_trait(Str, str_iterable);
|
||||||
/* NoneType */
|
/* NoneType */
|
||||||
|
@ -1149,12 +1164,12 @@ impl Context {
|
||||||
array_.register_trait(arr_t.clone(), array_show);
|
array_.register_trait(arr_t.clone(), array_show);
|
||||||
let mut array_iterable =
|
let mut array_iterable =
|
||||||
Self::builtin_methods(Some(poly("Iterable", vec![ty_tp(T.clone())])), 2);
|
Self::builtin_methods(Some(poly("Iterable", vec![ty_tp(T.clone())])), 2);
|
||||||
array_iterable.register_builtin_impl(
|
let t = fn0_met(
|
||||||
"iter",
|
array_t(T.clone(), TyParam::erased(Nat)),
|
||||||
fn0_met(Str, mono("ArrayIterator")),
|
poly("ArrayIterator", vec![ty_tp(T.clone())]),
|
||||||
Immutable,
|
)
|
||||||
Public,
|
.quantify();
|
||||||
);
|
array_iterable.register_builtin_py_impl("iter", t, Immutable, Public, Some("__iter__"));
|
||||||
array_.register_trait(arr_t.clone(), array_iterable);
|
array_.register_trait(arr_t.clone(), array_iterable);
|
||||||
/* Set */
|
/* Set */
|
||||||
let mut set_ =
|
let mut set_ =
|
||||||
|
@ -1278,8 +1293,10 @@ impl Context {
|
||||||
str_iterator.register_superclass(Obj, &obj);
|
str_iterator.register_superclass(Obj, &obj);
|
||||||
let mut array_iterator = Self::builtin_poly_class("ArrayIterator", vec![PS::t_nd("T")], 1);
|
let mut array_iterator = Self::builtin_poly_class("ArrayIterator", vec![PS::t_nd("T")], 1);
|
||||||
array_iterator.register_superclass(Obj, &obj);
|
array_iterator.register_superclass(Obj, &obj);
|
||||||
|
array_iterator.register_marker_trait(poly("Output", vec![ty_tp(T.clone())]));
|
||||||
let mut range_iterator = Self::builtin_poly_class("RangeIterator", vec![PS::t_nd("T")], 1);
|
let mut range_iterator = Self::builtin_poly_class("RangeIterator", vec![PS::t_nd("T")], 1);
|
||||||
range_iterator.register_superclass(Obj, &obj);
|
range_iterator.register_superclass(Obj, &obj);
|
||||||
|
range_iterator.register_marker_trait(poly("Output", vec![ty_tp(T.clone())]));
|
||||||
let mut obj_mut = Self::builtin_mono_class("Obj!", 2);
|
let mut obj_mut = Self::builtin_mono_class("Obj!", 2);
|
||||||
obj_mut.register_superclass(Obj, &obj);
|
obj_mut.register_superclass(Obj, &obj);
|
||||||
let mut obj_mut_mutable = Self::builtin_methods(Some(mono("Mutable")), 2);
|
let mut obj_mut_mutable = Self::builtin_methods(Some(mono("Mutable")), 2);
|
||||||
|
@ -1526,11 +1543,12 @@ impl Context {
|
||||||
range.register_trait(range_t.clone(), range_eq);
|
range.register_trait(range_t.clone(), range_eq);
|
||||||
let mut range_iterable =
|
let mut range_iterable =
|
||||||
Self::builtin_methods(Some(poly("Iterable", vec![ty_tp(T.clone())])), 2);
|
Self::builtin_methods(Some(poly("Iterable", vec![ty_tp(T.clone())])), 2);
|
||||||
range_iterable.register_builtin_impl(
|
range_iterable.register_builtin_py_impl(
|
||||||
"iter",
|
"iter",
|
||||||
fn0_met(Str, mono("RangeIterator")),
|
fn0_met(Str, mono("RangeIterator")),
|
||||||
Immutable,
|
Immutable,
|
||||||
Public,
|
Public,
|
||||||
|
Some("__iter__"),
|
||||||
);
|
);
|
||||||
range.register_trait(range_t.clone(), range_iterable);
|
range.register_trait(range_t.clone(), range_iterable);
|
||||||
let range_getitem_t = fn1_kw_met(range_t.clone(), anon(T.clone()), T.clone()).quantify();
|
let range_getitem_t = fn1_kw_met(range_t.clone(), anon(T.clone()), T.clone()).quantify();
|
||||||
|
@ -1897,6 +1915,14 @@ impl Context {
|
||||||
// TODO: register Del function object
|
// TODO: register Del function object
|
||||||
let t_del = nd_func(vec![kw("obj", Obj)], None, NoneType);
|
let t_del = nd_func(vec![kw("obj", Obj)], None, NoneType);
|
||||||
self.register_builtin_impl("Del", t_del, Immutable, Private);
|
self.register_builtin_impl("Del", t_del, Immutable, Private);
|
||||||
|
let patch_t = func(
|
||||||
|
vec![kw("Requirement", Type)],
|
||||||
|
None,
|
||||||
|
vec![kw("Impl", Type)],
|
||||||
|
TraitType,
|
||||||
|
);
|
||||||
|
let patch = ConstSubr::Builtin(BuiltinConstSubr::new("Patch", patch_func, patch_t, None));
|
||||||
|
self.register_builtin_const("Patch", Private, ValueObj::Subr(patch));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_builtin_procs(&mut self) {
|
fn init_builtin_procs(&mut self) {
|
||||||
|
|
|
@ -35,7 +35,7 @@ use crate::AccessKind;
|
||||||
use RegistrationMode::*;
|
use RegistrationMode::*;
|
||||||
use Visibility::*;
|
use Visibility::*;
|
||||||
|
|
||||||
use super::MethodInfo;
|
use super::{ContextKind, MethodInfo};
|
||||||
|
|
||||||
impl Context {
|
impl Context {
|
||||||
pub(crate) fn validate_var_sig_t(
|
pub(crate) fn validate_var_sig_t(
|
||||||
|
@ -151,6 +151,7 @@ impl Context {
|
||||||
) -> SingleTyCheckResult<&Context> {
|
) -> SingleTyCheckResult<&Context> {
|
||||||
self.get_mod(ident.inspect())
|
self.get_mod(ident.inspect())
|
||||||
.or_else(|| self.rec_get_type(ident.inspect()).map(|(_, ctx)| ctx))
|
.or_else(|| self.rec_get_type(ident.inspect()).map(|(_, ctx)| ctx))
|
||||||
|
.or_else(|| self.rec_get_patch(ident.inspect()))
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
TyCheckError::no_var_error(
|
TyCheckError::no_var_error(
|
||||||
self.cfg.input.clone(),
|
self.cfg.input.clone(),
|
||||||
|
@ -468,6 +469,26 @@ impl Context {
|
||||||
return Err(e);
|
return Err(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for patch in self.find_patches_of(obj.ref_t()) {
|
||||||
|
if let Some(vi) = patch
|
||||||
|
.locals
|
||||||
|
.get(ident.inspect())
|
||||||
|
.or_else(|| patch.decls.get(ident.inspect()))
|
||||||
|
{
|
||||||
|
self.validate_visibility(ident, vi, input, namespace)?;
|
||||||
|
return Ok(vi.clone());
|
||||||
|
}
|
||||||
|
for (_, methods_ctx) in patch.methods_list.iter() {
|
||||||
|
if let Some(vi) = methods_ctx
|
||||||
|
.locals
|
||||||
|
.get(ident.inspect())
|
||||||
|
.or_else(|| methods_ctx.decls.get(ident.inspect()))
|
||||||
|
{
|
||||||
|
self.validate_visibility(ident, vi, input, namespace)?;
|
||||||
|
return Ok(vi.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// TODO: dependent type widening
|
// TODO: dependent type widening
|
||||||
if let Some(parent) = self.get_outer().or_else(|| self.get_builtins()) {
|
if let Some(parent) = self.get_outer().or_else(|| self.get_builtins()) {
|
||||||
parent.rec_get_attr_info(obj, ident, input, namespace)
|
parent.rec_get_attr_info(obj, ident, input, namespace)
|
||||||
|
@ -607,7 +628,10 @@ impl Context {
|
||||||
line!() as usize,
|
line!() as usize,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
other => todo!("{other}"),
|
_other => Err(TyCheckError::dummy(
|
||||||
|
self.cfg.input.clone(),
|
||||||
|
line!() as usize,
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(TyCheckError::dummy(
|
Err(TyCheckError::dummy(
|
||||||
|
@ -701,7 +725,26 @@ impl Context {
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
// TODO: patch
|
for patch in self.find_patches_of(obj.ref_t()) {
|
||||||
|
if let Some(vi) = patch
|
||||||
|
.locals
|
||||||
|
.get(attr_name.inspect())
|
||||||
|
.or_else(|| patch.decls.get(attr_name.inspect()))
|
||||||
|
{
|
||||||
|
self.validate_visibility(attr_name, vi, input, namespace)?;
|
||||||
|
return Ok(vi.clone());
|
||||||
|
}
|
||||||
|
for (_, methods_ctx) in patch.methods_list.iter() {
|
||||||
|
if let Some(vi) = methods_ctx
|
||||||
|
.locals
|
||||||
|
.get(attr_name.inspect())
|
||||||
|
.or_else(|| methods_ctx.decls.get(attr_name.inspect()))
|
||||||
|
{
|
||||||
|
self.validate_visibility(attr_name, vi, input, namespace)?;
|
||||||
|
return Ok(vi.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Err(TyCheckError::no_attr_error(
|
Err(TyCheckError::no_attr_error(
|
||||||
self.cfg.input.clone(),
|
self.cfg.input.clone(),
|
||||||
line!() as usize,
|
line!() as usize,
|
||||||
|
@ -741,6 +784,7 @@ impl Context {
|
||||||
&& &self.name[..] != namespace
|
&& &self.name[..] != namespace
|
||||||
&& !namespace.contains(&self.name[..])
|
&& !namespace.contains(&self.name[..])
|
||||||
{
|
{
|
||||||
|
log!(err "{namespace}/{}", self.name);
|
||||||
Err(TyCheckError::visibility_error(
|
Err(TyCheckError::visibility_error(
|
||||||
input.clone(),
|
input.clone(),
|
||||||
line!() as usize,
|
line!() as usize,
|
||||||
|
@ -1879,19 +1923,9 @@ impl Context {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn _rec_get_patch(&self, name: &VarName) -> Option<&Context> {
|
pub(crate) fn all_patches(&self) -> Vec<&Context> {
|
||||||
if let Some(patch) = self.patches.get(name) {
|
|
||||||
Some(patch)
|
|
||||||
} else if let Some(outer) = self.get_outer().or_else(|| self.get_builtins()) {
|
|
||||||
outer._rec_get_patch(name)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn _all_patches(&self) -> Vec<&Context> {
|
|
||||||
if let Some(outer) = self.get_outer().or_else(|| self.get_builtins()) {
|
if let Some(outer) = self.get_outer().or_else(|| self.get_builtins()) {
|
||||||
[outer._all_patches(), self.patches.values().collect()].concat()
|
[outer.all_patches(), self.patches.values().collect()].concat()
|
||||||
} else {
|
} else {
|
||||||
self.patches.values().collect()
|
self.patches.values().collect()
|
||||||
}
|
}
|
||||||
|
@ -1984,15 +2018,9 @@ impl Context {
|
||||||
// TODO: poly type
|
// TODO: poly type
|
||||||
pub(crate) fn rec_get_self_t(&self) -> Option<Type> {
|
pub(crate) fn rec_get_self_t(&self) -> Option<Type> {
|
||||||
if self.kind.is_method_def() || self.kind.is_type() {
|
if self.kind.is_method_def() || self.kind.is_type() {
|
||||||
// let name = self.name.split(&[':', '.']).last().unwrap();
|
|
||||||
/*if let Some((t, _)) = self.rec_get_type(name) {
|
|
||||||
log!("{t}");
|
|
||||||
Some(t.clone())
|
|
||||||
} else {
|
|
||||||
log!("none");
|
|
||||||
None
|
|
||||||
}*/
|
|
||||||
Some(mono(self.name.clone()))
|
Some(mono(self.name.clone()))
|
||||||
|
} else if let ContextKind::PatchMethodDefs(t) = &self.kind {
|
||||||
|
Some(t.clone())
|
||||||
} else if let Some(outer) = self.get_outer() {
|
} else if let Some(outer) = self.get_outer() {
|
||||||
outer.rec_get_self_t()
|
outer.rec_get_self_t()
|
||||||
} else {
|
} else {
|
||||||
|
@ -2063,6 +2091,16 @@ impl Context {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn rec_get_patch(&self, name: &str) -> Option<&Context> {
|
||||||
|
if let Some(ctx) = self.patches.get(name) {
|
||||||
|
Some(ctx)
|
||||||
|
} else if let Some(outer) = self.get_outer().or_else(|| self.get_builtins()) {
|
||||||
|
outer.rec_get_patch(name)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_method_type_by_name(&self, name: &Identifier) -> SingleTyCheckResult<&MethodInfo> {
|
fn get_method_type_by_name(&self, name: &Identifier) -> SingleTyCheckResult<&MethodInfo> {
|
||||||
// TODO: min_by
|
// TODO: min_by
|
||||||
if let Some(candidates) = self.method_to_traits.get(name.inspect()) {
|
if let Some(candidates) = self.method_to_traits.get(name.inspect()) {
|
||||||
|
|
|
@ -232,6 +232,7 @@ pub enum ContextKind {
|
||||||
Proc,
|
Proc,
|
||||||
Class,
|
Class,
|
||||||
MethodDefs(Option<Type>), // Type: trait implemented
|
MethodDefs(Option<Type>), // Type: trait implemented
|
||||||
|
PatchMethodDefs(Type),
|
||||||
Trait,
|
Trait,
|
||||||
StructuralTrait,
|
StructuralTrait,
|
||||||
Patch(Type),
|
Patch(Type),
|
||||||
|
@ -270,6 +271,10 @@ impl ContextKind {
|
||||||
pub fn is_trait(&self) -> bool {
|
pub fn is_trait(&self) -> bool {
|
||||||
matches!(self, Self::Trait | Self::StructuralTrait)
|
matches!(self, Self::Trait | Self::StructuralTrait)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_patch(&self) -> bool {
|
||||||
|
matches!(self, Self::Patch(_) | Self::GluePatch(_))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 記号表に登録されているモードを表す
|
/// 記号表に登録されているモードを表す
|
||||||
|
@ -682,6 +687,31 @@ impl Context {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
pub fn poly_patch<S: Into<Str>>(
|
||||||
|
name: S,
|
||||||
|
base: Type,
|
||||||
|
params: Vec<ParamSpec>,
|
||||||
|
cfg: ErgConfig,
|
||||||
|
mod_cache: Option<SharedModuleCache>,
|
||||||
|
py_mod_cache: Option<SharedModuleCache>,
|
||||||
|
capacity: usize,
|
||||||
|
level: usize,
|
||||||
|
) -> Self {
|
||||||
|
let name = name.into();
|
||||||
|
Self::poly(
|
||||||
|
name,
|
||||||
|
cfg,
|
||||||
|
ContextKind::Patch(base),
|
||||||
|
params,
|
||||||
|
None,
|
||||||
|
mod_cache,
|
||||||
|
py_mod_cache,
|
||||||
|
capacity,
|
||||||
|
level,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn mono_trait<S: Into<Str>>(
|
pub fn mono_trait<S: Into<Str>>(
|
||||||
name: S,
|
name: S,
|
||||||
|
@ -730,6 +760,28 @@ impl Context {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn mono_patch<S: Into<Str>>(
|
||||||
|
name: S,
|
||||||
|
base: Type,
|
||||||
|
cfg: ErgConfig,
|
||||||
|
mod_cache: Option<SharedModuleCache>,
|
||||||
|
py_mod_cache: Option<SharedModuleCache>,
|
||||||
|
capacity: usize,
|
||||||
|
level: usize,
|
||||||
|
) -> Self {
|
||||||
|
Self::poly_patch(
|
||||||
|
name,
|
||||||
|
base,
|
||||||
|
vec![],
|
||||||
|
cfg,
|
||||||
|
mod_cache,
|
||||||
|
py_mod_cache,
|
||||||
|
capacity,
|
||||||
|
level,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn methods(
|
pub fn methods(
|
||||||
impl_trait: Option<Type>,
|
impl_trait: Option<Type>,
|
||||||
|
|
|
@ -81,6 +81,11 @@ impl Context {
|
||||||
let vis = ident.vis();
|
let vis = ident.vis();
|
||||||
let kind = id.map_or(VarKind::Declared, VarKind::Defined);
|
let kind = id.map_or(VarKind::Declared, VarKind::Defined);
|
||||||
let sig_t = self.instantiate_var_sig_t(sig.t_spec.as_ref(), opt_t, PreRegister)?;
|
let sig_t = self.instantiate_var_sig_t(sig.t_spec.as_ref(), opt_t, PreRegister)?;
|
||||||
|
let py_name = if let ContextKind::PatchMethodDefs(_base) = &self.kind {
|
||||||
|
Some(Str::from(format!("::{}{}", self.name, ident)))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
if let Some(_decl) = self.decls.remove(&ident.name) {
|
if let Some(_decl) = self.decls.remove(&ident.name) {
|
||||||
Err(TyCheckErrors::from(TyCheckError::duplicate_decl_error(
|
Err(TyCheckErrors::from(TyCheckError::duplicate_decl_error(
|
||||||
self.cfg.input.clone(),
|
self.cfg.input.clone(),
|
||||||
|
@ -90,10 +95,8 @@ impl Context {
|
||||||
ident.name.inspect(),
|
ident.name.inspect(),
|
||||||
)))
|
)))
|
||||||
} else {
|
} else {
|
||||||
self.future_defined_locals.insert(
|
let vi = VarInfo::new(sig_t, muty, vis, kind, None, self.impl_of(), py_name);
|
||||||
ident.name.clone(),
|
self.future_defined_locals.insert(ident.name.clone(), vi);
|
||||||
VarInfo::new(sig_t, muty, vis, kind, None, self.impl_of(), None),
|
|
||||||
);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -123,6 +126,11 @@ impl Context {
|
||||||
Ok(t) => (TyCheckErrors::empty(), t),
|
Ok(t) => (TyCheckErrors::empty(), t),
|
||||||
Err((errs, t)) => (errs, t),
|
Err((errs, t)) => (errs, t),
|
||||||
};
|
};
|
||||||
|
let py_name = if let ContextKind::PatchMethodDefs(_base) = &self.kind {
|
||||||
|
Some(Str::from(format!("::{}{}", self.name, sig.ident)))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
let vi = VarInfo::new(
|
let vi = VarInfo::new(
|
||||||
t,
|
t,
|
||||||
muty,
|
muty,
|
||||||
|
@ -130,7 +138,7 @@ impl Context {
|
||||||
kind,
|
kind,
|
||||||
Some(comptime_decos),
|
Some(comptime_decos),
|
||||||
self.impl_of(),
|
self.impl_of(),
|
||||||
None,
|
py_name,
|
||||||
);
|
);
|
||||||
if let Some(_decl) = self.decls.remove(name) {
|
if let Some(_decl) = self.decls.remove(name) {
|
||||||
Err(TyCheckErrors::from(TyCheckError::duplicate_decl_error(
|
Err(TyCheckErrors::from(TyCheckError::duplicate_decl_error(
|
||||||
|
@ -182,8 +190,15 @@ impl Context {
|
||||||
}
|
}
|
||||||
self.validate_var_sig_t(ident, sig.t_spec.as_ref(), body_t, Normal)?;
|
self.validate_var_sig_t(ident, sig.t_spec.as_ref(), body_t, Normal)?;
|
||||||
let muty = Mutability::from(&ident.inspect()[..]);
|
let muty = Mutability::from(&ident.inspect()[..]);
|
||||||
self.decls.remove(ident.inspect());
|
let py_name = if let Some(vi) = self
|
||||||
self.future_defined_locals.remove(ident.inspect());
|
.decls
|
||||||
|
.remove(ident.inspect())
|
||||||
|
.or_else(|| self.future_defined_locals.remove(ident.inspect()))
|
||||||
|
{
|
||||||
|
vi.py_name
|
||||||
|
} else {
|
||||||
|
py_name
|
||||||
|
};
|
||||||
let vis = ident.vis();
|
let vis = ident.vis();
|
||||||
let vi = VarInfo::new(
|
let vi = VarInfo::new(
|
||||||
body_t.clone(),
|
body_t.clone(),
|
||||||
|
@ -456,7 +471,7 @@ impl Context {
|
||||||
};
|
};
|
||||||
sub_t.lift();
|
sub_t.lift();
|
||||||
let found_t = self.generalize_t(sub_t);
|
let found_t = self.generalize_t(sub_t);
|
||||||
if let Some(vi) = self.decls.remove(name) {
|
let py_name = if let Some(vi) = self.decls.remove(name) {
|
||||||
if !self.supertype_of(&vi.t, &found_t) {
|
if !self.supertype_of(&vi.t, &found_t) {
|
||||||
return Err(TyCheckErrors::from(TyCheckError::violate_decl_error(
|
return Err(TyCheckErrors::from(TyCheckError::violate_decl_error(
|
||||||
self.cfg.input.clone(),
|
self.cfg.input.clone(),
|
||||||
|
@ -468,7 +483,10 @@ impl Context {
|
||||||
&found_t,
|
&found_t,
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
}
|
vi.py_name
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
let comptime_decos = decorators
|
let comptime_decos = decorators
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|deco| match &deco.0 {
|
.filter_map(|deco| match &deco.0 {
|
||||||
|
@ -485,7 +503,7 @@ impl Context {
|
||||||
VarKind::Defined(id),
|
VarKind::Defined(id),
|
||||||
Some(comptime_decos),
|
Some(comptime_decos),
|
||||||
self.impl_of(),
|
self.impl_of(),
|
||||||
None,
|
py_name,
|
||||||
);
|
);
|
||||||
let t = vi.t.clone();
|
let t = vi.t.clone();
|
||||||
log!(info "Registered {}::{name}: {t}", self.name);
|
log!(info "Registered {}::{name}: {t}", self.name);
|
||||||
|
@ -548,6 +566,11 @@ impl Context {
|
||||||
total_errs.extend(errs.into_iter());
|
total_errs.extend(errs.into_iter());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ast::Expr::PatchDef(patch_def) => {
|
||||||
|
if let Err(errs) = self.preregister_def(&patch_def.def) {
|
||||||
|
total_errs.extend(errs.into_iter());
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -950,6 +973,23 @@ impl Context {
|
||||||
todo!("polymorphic type definition is not supported yet");
|
todo!("polymorphic type definition is not supported yet");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
GenTypeObj::Patch(_) => {
|
||||||
|
if gen.typ().is_monomorphic() {
|
||||||
|
let base = enum_unwrap!(gen.require_or_sup().unwrap(), TypeObj::Builtin);
|
||||||
|
let ctx = Self::mono_patch(
|
||||||
|
gen.typ().qual_name(),
|
||||||
|
base.clone(),
|
||||||
|
self.cfg.clone(),
|
||||||
|
self.mod_cache.clone(),
|
||||||
|
self.py_mod_cache.clone(),
|
||||||
|
2,
|
||||||
|
self.level,
|
||||||
|
);
|
||||||
|
self.register_gen_mono_patch(ident, gen, ctx, Const);
|
||||||
|
} else {
|
||||||
|
todo!("polymorphic patch definition is not supported yet");
|
||||||
|
}
|
||||||
|
}
|
||||||
other => todo!("{other:?}"),
|
other => todo!("{other:?}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1046,6 +1086,72 @@ impl Context {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn register_gen_mono_patch(
|
||||||
|
&mut self,
|
||||||
|
ident: &Identifier,
|
||||||
|
gen: GenTypeObj,
|
||||||
|
ctx: Self,
|
||||||
|
muty: Mutability,
|
||||||
|
) {
|
||||||
|
// FIXME: not panic but error
|
||||||
|
// FIXME: recursive search
|
||||||
|
if self.patches.contains_key(ident.inspect()) {
|
||||||
|
panic!("{ident} has already been registered");
|
||||||
|
} else if self.rec_get_const_obj(ident.inspect()).is_some() && ident.vis().is_private() {
|
||||||
|
panic!("{ident} has already been registered as const");
|
||||||
|
} else {
|
||||||
|
let t = gen.typ().clone();
|
||||||
|
let meta_t = gen.meta_type();
|
||||||
|
let name = &ident.name;
|
||||||
|
let id = DefId(get_hash(&(&self.name, &name)));
|
||||||
|
self.decls.insert(
|
||||||
|
name.clone(),
|
||||||
|
VarInfo::new(
|
||||||
|
meta_t,
|
||||||
|
muty,
|
||||||
|
ident.vis(),
|
||||||
|
VarKind::Defined(id),
|
||||||
|
None,
|
||||||
|
self.impl_of(),
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
self.consts
|
||||||
|
.insert(name.clone(), ValueObj::Type(TypeObj::Generated(gen)));
|
||||||
|
for impl_trait in ctx.super_traits.iter() {
|
||||||
|
if let Some(impls) = self.trait_impls.get_mut(&impl_trait.qual_name()) {
|
||||||
|
impls.insert(TypeRelationInstance::new(t.clone(), impl_trait.clone()));
|
||||||
|
} else {
|
||||||
|
self.trait_impls.insert(
|
||||||
|
impl_trait.qual_name(),
|
||||||
|
set![TypeRelationInstance::new(t.clone(), impl_trait.clone())],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (trait_method, vi) in ctx.decls.iter() {
|
||||||
|
if let Some(types) = self.method_to_traits.get_mut(trait_method.inspect()) {
|
||||||
|
types.push(MethodInfo::new(t.clone(), vi.clone()));
|
||||||
|
} else {
|
||||||
|
self.method_to_traits.insert(
|
||||||
|
trait_method.inspect().clone(),
|
||||||
|
vec![MethodInfo::new(t.clone(), vi.clone())],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (class_method, vi) in ctx.locals.iter() {
|
||||||
|
if let Some(types) = self.method_to_classes.get_mut(class_method.inspect()) {
|
||||||
|
types.push(MethodInfo::new(t.clone(), vi.clone()));
|
||||||
|
} else {
|
||||||
|
self.method_to_classes.insert(
|
||||||
|
class_method.inspect().clone(),
|
||||||
|
vec![MethodInfo::new(t.clone(), vi.clone())],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.patches.insert(name.clone(), ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn import_mod(
|
pub(crate) fn import_mod(
|
||||||
&mut self,
|
&mut self,
|
||||||
kind: OperationKind,
|
kind: OperationKind,
|
||||||
|
|
|
@ -358,6 +358,7 @@ impl Context {
|
||||||
Variance::Covariant => Ok(sub_t),
|
Variance::Covariant => Ok(sub_t),
|
||||||
Variance::Contravariant => Ok(super_t),
|
Variance::Contravariant => Ok(super_t),
|
||||||
Variance::Invariant => {
|
Variance::Invariant => {
|
||||||
|
// need to check if sub_t == super_t
|
||||||
if self.supertype_of(&sub_t, &super_t) {
|
if self.supertype_of(&sub_t, &super_t) {
|
||||||
Ok(sub_t)
|
Ok(sub_t)
|
||||||
} else {
|
} else {
|
||||||
|
@ -772,6 +773,12 @@ impl Context {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
hir::Expr::PatchDef(patch_def) => {
|
||||||
|
for def in patch_def.methods.iter_mut() {
|
||||||
|
self.resolve_expr_t(def)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
hir::Expr::AttrDef(attr_def) => {
|
hir::Expr::AttrDef(attr_def) => {
|
||||||
// REVIEW: attr_def.attr is not dereferenced
|
// REVIEW: attr_def.attr is not dereferenced
|
||||||
for chunk in attr_def.block.iter_mut() {
|
for chunk in attr_def.block.iter_mut() {
|
||||||
|
|
|
@ -95,11 +95,19 @@ impl SideEffectChecker {
|
||||||
self.check_def(def);
|
self.check_def(def);
|
||||||
}
|
}
|
||||||
Expr::ClassDef(class_def) => {
|
Expr::ClassDef(class_def) => {
|
||||||
|
self.check_expr(class_def.require_or_sup.as_ref());
|
||||||
// TODO: grow
|
// TODO: grow
|
||||||
for def in class_def.methods.iter() {
|
for def in class_def.methods.iter() {
|
||||||
self.check_expr(def);
|
self.check_expr(def);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Expr::PatchDef(patch_def) => {
|
||||||
|
self.check_expr(patch_def.base.as_ref());
|
||||||
|
// TODO: grow
|
||||||
|
for def in patch_def.methods.iter() {
|
||||||
|
self.check_expr(def);
|
||||||
|
}
|
||||||
|
}
|
||||||
Expr::Call(call) => {
|
Expr::Call(call) => {
|
||||||
for parg in call.args.pos_args.iter() {
|
for parg in call.args.pos_args.iter() {
|
||||||
self.check_expr(&parg.expr);
|
self.check_expr(&parg.expr);
|
||||||
|
@ -271,10 +279,17 @@ impl SideEffectChecker {
|
||||||
self.check_def(def);
|
self.check_def(def);
|
||||||
}
|
}
|
||||||
Expr::ClassDef(class_def) => {
|
Expr::ClassDef(class_def) => {
|
||||||
|
self.check_expr(class_def.require_or_sup.as_ref());
|
||||||
for def in class_def.methods.iter() {
|
for def in class_def.methods.iter() {
|
||||||
self.check_expr(def);
|
self.check_expr(def);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Expr::PatchDef(patch_def) => {
|
||||||
|
self.check_expr(patch_def.base.as_ref());
|
||||||
|
for def in patch_def.methods.iter() {
|
||||||
|
self.check_expr(def);
|
||||||
|
}
|
||||||
|
}
|
||||||
Expr::Array(array) => match array {
|
Expr::Array(array) => match array {
|
||||||
Array::Normal(arr) => {
|
Array::Normal(arr) => {
|
||||||
for elem in arr.elems.pos_args.iter() {
|
for elem in arr.elems.pos_args.iter() {
|
||||||
|
|
|
@ -442,8 +442,12 @@ impl Identifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// show dot + name (no qual_name & type)
|
/// show dot + name (no qual_name & type)
|
||||||
pub fn show(&self) -> String {
|
pub fn to_string_without_type(&self) -> String {
|
||||||
format!("{}{}", fmt_option!(self.dot), self.name)
|
if self.dot.is_some() {
|
||||||
|
format!(".{}", self.name)
|
||||||
|
} else {
|
||||||
|
format!("::{}", self.name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_procedural(&self) -> bool {
|
pub fn is_procedural(&self) -> bool {
|
||||||
|
@ -1410,7 +1414,7 @@ impl NestedDisplay for SubrSignature {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{}{} (: {})",
|
"{}{} (: {})",
|
||||||
self.ident.show(),
|
self.ident.to_string_without_type(),
|
||||||
self.params,
|
self.params,
|
||||||
self.ident.t()
|
self.ident.t()
|
||||||
)
|
)
|
||||||
|
@ -1781,6 +1785,54 @@ impl ClassDef {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct PatchDef {
|
||||||
|
pub sig: Signature,
|
||||||
|
pub base: Box<Expr>,
|
||||||
|
pub methods: Block,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NestedDisplay for PatchDef {
|
||||||
|
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result {
|
||||||
|
write!(f, "{} = Patch ", self.sig)?;
|
||||||
|
self.base.fmt_nest(f, level)?;
|
||||||
|
writeln!(f, ":")?;
|
||||||
|
self.methods.fmt_nest(f, level + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_display_from_nested!(PatchDef);
|
||||||
|
impl_locational!(PatchDef, sig);
|
||||||
|
|
||||||
|
impl HasType for PatchDef {
|
||||||
|
#[inline]
|
||||||
|
fn ref_t(&self) -> &Type {
|
||||||
|
Type::NONE
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn ref_mut_t(&mut self) -> &mut Type {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn signature_t(&self) -> Option<&Type> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn signature_mut_t(&mut self) -> Option<&mut Type> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PatchDef {
|
||||||
|
pub fn new(sig: Signature, base: Expr, methods: Block) -> Self {
|
||||||
|
Self {
|
||||||
|
sig,
|
||||||
|
base: Box::new(base),
|
||||||
|
methods,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct AttrDef {
|
pub struct AttrDef {
|
||||||
pub attr: Accessor,
|
pub attr: Accessor,
|
||||||
|
@ -1881,6 +1933,7 @@ pub enum Expr {
|
||||||
Lambda(Lambda),
|
Lambda(Lambda),
|
||||||
Def(Def),
|
Def(Def),
|
||||||
ClassDef(ClassDef),
|
ClassDef(ClassDef),
|
||||||
|
PatchDef(PatchDef),
|
||||||
AttrDef(AttrDef),
|
AttrDef(AttrDef),
|
||||||
TypeAsc(TypeAscription),
|
TypeAsc(TypeAscription),
|
||||||
Code(Block), // code object
|
Code(Block), // code object
|
||||||
|
@ -1888,10 +1941,10 @@ pub enum Expr {
|
||||||
Import(Accessor),
|
Import(Accessor),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_nested_display_for_chunk_enum!(Expr; Lit, Accessor, Array, Tuple, Dict, Record, BinOp, UnaryOp, Call, Lambda, Def, ClassDef, AttrDef, Code, Compound, TypeAsc, Set, Import);
|
impl_nested_display_for_chunk_enum!(Expr; Lit, Accessor, Array, Tuple, Dict, Record, BinOp, UnaryOp, Call, Lambda, Def, ClassDef, PatchDef, AttrDef, Code, Compound, TypeAsc, Set, Import);
|
||||||
impl_display_from_nested!(Expr);
|
impl_display_from_nested!(Expr);
|
||||||
impl_locational_for_enum!(Expr; Lit, Accessor, Array, Tuple, Dict, Record, BinOp, UnaryOp, Call, Lambda, Def, ClassDef, AttrDef, Code, Compound, TypeAsc, Set, Import);
|
impl_locational_for_enum!(Expr; Lit, Accessor, Array, Tuple, Dict, Record, BinOp, UnaryOp, Call, Lambda, Def, ClassDef, PatchDef, AttrDef, Code, Compound, TypeAsc, Set, Import);
|
||||||
impl_t_for_enum!(Expr; Lit, Accessor, Array, Tuple, Dict, Record, BinOp, UnaryOp, Call, Lambda, Def, ClassDef, AttrDef, Code, Compound, TypeAsc, Set, Import);
|
impl_t_for_enum!(Expr; Lit, Accessor, Array, Tuple, Dict, Record, BinOp, UnaryOp, Call, Lambda, Def, ClassDef, PatchDef, AttrDef, Code, Compound, TypeAsc, Set, Import);
|
||||||
|
|
||||||
impl Default for Expr {
|
impl Default for Expr {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
|
|
@ -139,6 +139,11 @@ impl<'a> Linker<'a> {
|
||||||
self.resolve_pymod_path(def);
|
self.resolve_pymod_path(def);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Expr::PatchDef(patch_def) => {
|
||||||
|
for def in patch_def.methods.iter_mut() {
|
||||||
|
self.resolve_pymod_path(def);
|
||||||
|
}
|
||||||
|
}
|
||||||
Expr::AttrDef(attr_def) => {
|
Expr::AttrDef(attr_def) => {
|
||||||
// REVIEW:
|
// REVIEW:
|
||||||
for chunk in attr_def.block.iter_mut() {
|
for chunk in attr_def.block.iter_mut() {
|
||||||
|
@ -255,6 +260,11 @@ impl<'a> Linker<'a> {
|
||||||
self.replace_import(def);
|
self.replace_import(def);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Expr::PatchDef(patch_def) => {
|
||||||
|
for def in patch_def.methods.iter_mut() {
|
||||||
|
self.replace_import(def);
|
||||||
|
}
|
||||||
|
}
|
||||||
Expr::AttrDef(attr_def) => {
|
Expr::AttrDef(attr_def) => {
|
||||||
// REVIEW:
|
// REVIEW:
|
||||||
for chunk in attr_def.block.iter_mut() {
|
for chunk in attr_def.block.iter_mut() {
|
||||||
|
|
|
@ -220,8 +220,15 @@ impl ASTLowerer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hir::Expr::ClassDef(cl_def) => {
|
hir::Expr::ClassDef(class_def) => {
|
||||||
for chunk in cl_def.methods.iter() {
|
for chunk in class_def.methods.iter() {
|
||||||
|
if let Err(ws) = self.use_check(chunk, mode) {
|
||||||
|
warns.extend(ws);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hir::Expr::PatchDef(patch_def) => {
|
||||||
|
for chunk in patch_def.methods.iter() {
|
||||||
if let Err(ws) = self.use_check(chunk, mode) {
|
if let Err(ws) = self.use_check(chunk, mode) {
|
||||||
warns.extend(ws);
|
warns.extend(ws);
|
||||||
}
|
}
|
||||||
|
@ -1287,7 +1294,7 @@ impl ASTLowerer {
|
||||||
} else {
|
} else {
|
||||||
todo!()
|
todo!()
|
||||||
};
|
};
|
||||||
let require_or_sup = self.get_require_or_sup(hir_def.body.block.remove(0));
|
let require_or_sup = self.get_require_or_sup_or_base(hir_def.body.block.remove(0));
|
||||||
Ok(hir::ClassDef::new(
|
Ok(hir::ClassDef::new(
|
||||||
type_obj.clone(),
|
type_obj.clone(),
|
||||||
hir_def.sig,
|
hir_def.sig,
|
||||||
|
@ -1298,6 +1305,71 @@ impl ASTLowerer {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn lower_patch_def(&mut self, class_def: ast::PatchDef) -> LowerResult<hir::PatchDef> {
|
||||||
|
log!(info "entered {}({class_def})", fn_name!());
|
||||||
|
let base_t = {
|
||||||
|
let base_t_expr =
|
||||||
|
enum_unwrap!(class_def.def.body.block.get(0).unwrap(), ast::Expr::Call)
|
||||||
|
.args
|
||||||
|
.get_left_or_key("Base")
|
||||||
|
.unwrap();
|
||||||
|
let spec = Parser::expr_to_type_spec(base_t_expr.clone()).unwrap();
|
||||||
|
let mut dummy_tv_cache = TyVarCache::new(self.ctx.level, &self.ctx);
|
||||||
|
self.ctx.instantiate_typespec(
|
||||||
|
&spec,
|
||||||
|
None,
|
||||||
|
&mut dummy_tv_cache,
|
||||||
|
RegistrationMode::Normal,
|
||||||
|
false,
|
||||||
|
)?
|
||||||
|
};
|
||||||
|
let mut hir_def = self.lower_def(class_def.def)?;
|
||||||
|
let base = self.get_require_or_sup_or_base(hir_def.body.block.remove(0));
|
||||||
|
let mut hir_methods = hir::Block::empty();
|
||||||
|
for mut methods in class_def.methods_list.into_iter() {
|
||||||
|
let kind = ContextKind::PatchMethodDefs(base_t.clone());
|
||||||
|
self.ctx
|
||||||
|
.grow(hir_def.sig.ident().inspect(), kind, hir_def.sig.vis(), None);
|
||||||
|
for attr in methods.attrs.iter_mut() {
|
||||||
|
match attr {
|
||||||
|
ast::ClassAttr::Def(def) => {
|
||||||
|
if methods.vis.is(TokenKind::Dot) {
|
||||||
|
def.sig.ident_mut().unwrap().dot = Some(Token::new(
|
||||||
|
TokenKind::Dot,
|
||||||
|
".",
|
||||||
|
def.sig.ln_begin().unwrap(),
|
||||||
|
def.sig.col_begin().unwrap(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
self.ctx.preregister_def(def)?;
|
||||||
|
}
|
||||||
|
ast::ClassAttr::Decl(_decl) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for attr in methods.attrs.into_iter() {
|
||||||
|
match attr {
|
||||||
|
ast::ClassAttr::Def(def) => match self.lower_def(def) {
|
||||||
|
Ok(def) => {
|
||||||
|
hir_methods.push(hir::Expr::Def(def));
|
||||||
|
}
|
||||||
|
Err(errs) => {
|
||||||
|
self.errs.extend(errs);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ast::ClassAttr::Decl(decl) => {
|
||||||
|
let decl = self.lower_type_asc(decl)?;
|
||||||
|
hir_methods.push(hir::Expr::TypeAsc(decl));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Err(mut errs) = self.ctx.check_decls() {
|
||||||
|
self.errs.append(&mut errs);
|
||||||
|
}
|
||||||
|
self.push_patch();
|
||||||
|
}
|
||||||
|
Ok(hir::PatchDef::new(hir_def.sig, base, hir_methods))
|
||||||
|
}
|
||||||
|
|
||||||
fn register_trait_impl(
|
fn register_trait_impl(
|
||||||
&mut self,
|
&mut self,
|
||||||
class: &Type,
|
class: &Type,
|
||||||
|
@ -1561,16 +1633,56 @@ impl ASTLowerer {
|
||||||
.push((ClassDefType::Simple(class), methods));
|
.push((ClassDefType::Simple(class), methods));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn push_patch(&mut self) {
|
||||||
|
let methods = self.ctx.pop();
|
||||||
|
let ContextKind::PatchMethodDefs(base) = &methods.kind else { unreachable!() };
|
||||||
|
let patch_name = *methods.name.split_with(&["::", "."]).last().unwrap();
|
||||||
|
let patch_root = self
|
||||||
|
.ctx
|
||||||
|
.patches
|
||||||
|
.get_mut(patch_name)
|
||||||
|
.unwrap_or_else(|| todo!("{} not found", methods.name));
|
||||||
|
for (newly_defined_name, vi) in methods.locals.clone().into_iter() {
|
||||||
|
for (_, already_defined_methods) in patch_root.methods_list.iter_mut() {
|
||||||
|
// TODO: 特殊化なら同じ名前でもOK
|
||||||
|
// TODO: 定義のメソッドもエラー表示
|
||||||
|
if let Some((_already_defined_name, already_defined_vi)) =
|
||||||
|
already_defined_methods.get_local_kv(newly_defined_name.inspect())
|
||||||
|
{
|
||||||
|
if already_defined_vi.kind != VarKind::Auto
|
||||||
|
&& already_defined_vi.impl_of == vi.impl_of
|
||||||
|
{
|
||||||
|
self.errs.push(LowerError::duplicate_definition_error(
|
||||||
|
self.cfg.input.clone(),
|
||||||
|
line!() as usize,
|
||||||
|
newly_defined_name.loc(),
|
||||||
|
methods.caused_by(),
|
||||||
|
newly_defined_name.inspect(),
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
already_defined_methods
|
||||||
|
.locals
|
||||||
|
.remove(&newly_defined_name.inspect()[..]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
patch_root
|
||||||
|
.methods_list
|
||||||
|
.push((ClassDefType::Simple(base.clone()), methods));
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(clippy::only_used_in_recursion)]
|
#[allow(clippy::only_used_in_recursion)]
|
||||||
fn get_require_or_sup(&self, expr: hir::Expr) -> hir::Expr {
|
fn get_require_or_sup_or_base(&self, expr: hir::Expr) -> hir::Expr {
|
||||||
match expr {
|
match expr {
|
||||||
acc @ hir::Expr::Accessor(_) => acc,
|
acc @ hir::Expr::Accessor(_) => acc,
|
||||||
hir::Expr::Call(mut call) => match call.obj.show_acc().as_ref().map(|s| &s[..]) {
|
hir::Expr::Call(mut call) => match call.obj.show_acc().as_ref().map(|s| &s[..]) {
|
||||||
Some("Class") => call.args.remove_left_or_key("Requirement").unwrap(),
|
Some("Class") => call.args.remove_left_or_key("Requirement").unwrap(),
|
||||||
Some("Inherit") => call.args.remove_left_or_key("Super").unwrap(),
|
Some("Inherit") => call.args.remove_left_or_key("Super").unwrap(),
|
||||||
Some("Inheritable") => {
|
Some("Inheritable") => {
|
||||||
self.get_require_or_sup(call.args.remove_left_or_key("Class").unwrap())
|
self.get_require_or_sup_or_base(call.args.remove_left_or_key("Class").unwrap())
|
||||||
}
|
}
|
||||||
|
Some("Patch") => call.args.remove_left_or_key("Base").unwrap(),
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
},
|
},
|
||||||
other => todo!("{other}"),
|
other => todo!("{other}"),
|
||||||
|
@ -1637,6 +1749,7 @@ impl ASTLowerer {
|
||||||
ast::Expr::Lambda(lambda) => Ok(hir::Expr::Lambda(self.lower_lambda(lambda)?)),
|
ast::Expr::Lambda(lambda) => Ok(hir::Expr::Lambda(self.lower_lambda(lambda)?)),
|
||||||
ast::Expr::Def(def) => Ok(hir::Expr::Def(self.lower_def(def)?)),
|
ast::Expr::Def(def) => Ok(hir::Expr::Def(self.lower_def(def)?)),
|
||||||
ast::Expr::ClassDef(defs) => Ok(hir::Expr::ClassDef(self.lower_class_def(defs)?)),
|
ast::Expr::ClassDef(defs) => Ok(hir::Expr::ClassDef(self.lower_class_def(defs)?)),
|
||||||
|
ast::Expr::PatchDef(defs) => Ok(hir::Expr::PatchDef(self.lower_patch_def(defs)?)),
|
||||||
ast::Expr::TypeAsc(tasc) => Ok(hir::Expr::TypeAsc(self.lower_type_asc(tasc)?)),
|
ast::Expr::TypeAsc(tasc) => Ok(hir::Expr::TypeAsc(self.lower_type_asc(tasc)?)),
|
||||||
other => todo!("{other}"),
|
other => todo!("{other}"),
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,6 +126,18 @@ impl OwnershipChecker {
|
||||||
self.check_block(&def.body.block);
|
self.check_block(&def.body.block);
|
||||||
self.path_stack.pop();
|
self.path_stack.pop();
|
||||||
}
|
}
|
||||||
|
Expr::ClassDef(class_def) => {
|
||||||
|
self.check_expr(&class_def.require_or_sup, Ownership::Owned, false);
|
||||||
|
for def in class_def.methods.iter() {
|
||||||
|
self.check_expr(def, Ownership::Owned, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expr::PatchDef(patch_def) => {
|
||||||
|
self.check_expr(&patch_def.base, Ownership::Owned, false);
|
||||||
|
for def in patch_def.methods.iter() {
|
||||||
|
self.check_expr(def, Ownership::Owned, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
// Access in chunks does not drop variables (e.g., access in REPL)
|
// Access in chunks does not drop variables (e.g., access in REPL)
|
||||||
Expr::Accessor(acc) => self.check_acc(acc, ownership, chunk),
|
Expr::Accessor(acc) => self.check_acc(acc, ownership, chunk),
|
||||||
// TODO: referenced
|
// TODO: referenced
|
||||||
|
|
|
@ -4,7 +4,7 @@ use erg_common::log;
|
||||||
use erg_common::traits::{Locational, Stream};
|
use erg_common::traits::{Locational, Stream};
|
||||||
use erg_common::Str;
|
use erg_common::Str;
|
||||||
|
|
||||||
use erg_parser::ast::{ClassDef, Expr, Methods, Module, PreDeclTypeSpec, TypeSpec, AST};
|
use erg_parser::ast::{ClassDef, Expr, Methods, Module, PatchDef, PreDeclTypeSpec, TypeSpec, AST};
|
||||||
|
|
||||||
use crate::error::{TyCheckError, TyCheckErrors};
|
use crate::error::{TyCheckError, TyCheckErrors};
|
||||||
|
|
||||||
|
@ -46,6 +46,14 @@ impl Reorderer {
|
||||||
let type_def = ClassDef::new(def, vec![]);
|
let type_def = ClassDef::new(def, vec![]);
|
||||||
new.push(Expr::ClassDef(type_def));
|
new.push(Expr::ClassDef(type_def));
|
||||||
}
|
}
|
||||||
|
Some("Patch") => {
|
||||||
|
self.def_root_pos_map.insert(
|
||||||
|
def.sig.ident().unwrap().inspect().clone(),
|
||||||
|
new.len(),
|
||||||
|
);
|
||||||
|
let type_def = PatchDef::new(def, vec![]);
|
||||||
|
new.push(Expr::PatchDef(type_def));
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
new.push(Expr::Def(def));
|
new.push(Expr::Def(def));
|
||||||
}
|
}
|
||||||
|
@ -97,12 +105,17 @@ impl Reorderer {
|
||||||
|
|
||||||
fn link_methods(&mut self, name: Str, new: &mut Vec<Expr>, methods: Methods) {
|
fn link_methods(&mut self, name: Str, new: &mut Vec<Expr>, methods: Methods) {
|
||||||
if let Some(pos) = self.def_root_pos_map.get(&name) {
|
if let Some(pos) = self.def_root_pos_map.get(&name) {
|
||||||
let mut class_def = match new.remove(*pos) {
|
match new.remove(*pos) {
|
||||||
Expr::ClassDef(class_def) => class_def,
|
Expr::ClassDef(mut class_def) => {
|
||||||
|
class_def.methods_list.push(methods);
|
||||||
|
new.insert(*pos, Expr::ClassDef(class_def));
|
||||||
|
}
|
||||||
|
Expr::PatchDef(mut patch_def) => {
|
||||||
|
patch_def.methods_list.push(methods);
|
||||||
|
new.insert(*pos, Expr::PatchDef(patch_def));
|
||||||
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
}
|
||||||
class_def.methods_list.push(methods);
|
|
||||||
new.insert(*pos, Expr::ClassDef(class_def));
|
|
||||||
} else {
|
} else {
|
||||||
let similar_name = self
|
let similar_name = self
|
||||||
.def_root_pos_map
|
.def_root_pos_map
|
||||||
|
|
|
@ -130,6 +130,23 @@ impl UnionTypeObj {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub struct PatchObj {
|
||||||
|
pub t: Type,
|
||||||
|
pub base: Box<TypeObj>,
|
||||||
|
pub impls: Option<Box<TypeObj>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PatchObj {
|
||||||
|
pub fn new(t: Type, base: TypeObj, impls: Option<TypeObj>) -> Self {
|
||||||
|
Self {
|
||||||
|
t,
|
||||||
|
base: Box::new(base),
|
||||||
|
impls: impls.map(Box::new),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub enum GenTypeObj {
|
pub enum GenTypeObj {
|
||||||
Class(ClassTypeObj),
|
Class(ClassTypeObj),
|
||||||
|
@ -138,6 +155,7 @@ pub enum GenTypeObj {
|
||||||
Subtrait(SubsumedTypeObj),
|
Subtrait(SubsumedTypeObj),
|
||||||
StructuralTrait(TraitTypeObj),
|
StructuralTrait(TraitTypeObj),
|
||||||
Union(UnionTypeObj),
|
Union(UnionTypeObj),
|
||||||
|
Patch(PatchObj),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for GenTypeObj {
|
impl fmt::Display for GenTypeObj {
|
||||||
|
@ -164,6 +182,10 @@ impl GenTypeObj {
|
||||||
GenTypeObj::Trait(TraitTypeObj::new(t, require, impls))
|
GenTypeObj::Trait(TraitTypeObj::new(t, require, impls))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn patch(t: Type, base: TypeObj, impls: Option<TypeObj>) -> Self {
|
||||||
|
GenTypeObj::Patch(PatchObj::new(t, base, impls))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn subsumed(
|
pub fn subsumed(
|
||||||
t: Type,
|
t: Type,
|
||||||
sup: TypeObj,
|
sup: TypeObj,
|
||||||
|
@ -184,6 +206,7 @@ impl GenTypeObj {
|
||||||
Self::Trait(trait_) => Some(trait_.require.as_ref()),
|
Self::Trait(trait_) => Some(trait_.require.as_ref()),
|
||||||
Self::Subtrait(subtrait) => Some(subtrait.sup.as_ref()),
|
Self::Subtrait(subtrait) => Some(subtrait.sup.as_ref()),
|
||||||
Self::StructuralTrait(trait_) => Some(trait_.require.as_ref()),
|
Self::StructuralTrait(trait_) => Some(trait_.require.as_ref()),
|
||||||
|
Self::Patch(patch) => Some(patch.base.as_ref()),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -193,6 +216,7 @@ impl GenTypeObj {
|
||||||
Self::Class(class) => class.impls.as_ref().map(|x| x.as_ref()),
|
Self::Class(class) => class.impls.as_ref().map(|x| x.as_ref()),
|
||||||
Self::Subclass(subclass) => subclass.impls.as_ref().map(|x| x.as_ref()),
|
Self::Subclass(subclass) => subclass.impls.as_ref().map(|x| x.as_ref()),
|
||||||
Self::Subtrait(subtrait) => subtrait.impls.as_ref().map(|x| x.as_ref()),
|
Self::Subtrait(subtrait) => subtrait.impls.as_ref().map(|x| x.as_ref()),
|
||||||
|
Self::Patch(patch) => patch.impls.as_ref().map(|x| x.as_ref()),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -202,6 +226,7 @@ impl GenTypeObj {
|
||||||
Self::Class(class) => Some(&mut class.impls),
|
Self::Class(class) => Some(&mut class.impls),
|
||||||
Self::Subclass(subclass) => Some(&mut subclass.impls),
|
Self::Subclass(subclass) => Some(&mut subclass.impls),
|
||||||
Self::Subtrait(subtrait) => Some(&mut subtrait.impls),
|
Self::Subtrait(subtrait) => Some(&mut subtrait.impls),
|
||||||
|
Self::Patch(patch) => Some(&mut patch.impls),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -218,6 +243,7 @@ impl GenTypeObj {
|
||||||
match self {
|
match self {
|
||||||
Self::Class(_) | Self::Subclass(_) => Type::ClassType,
|
Self::Class(_) | Self::Subclass(_) => Type::ClassType,
|
||||||
Self::Trait(_) | Self::Subtrait(_) | Self::StructuralTrait(_) => Type::TraitType,
|
Self::Trait(_) | Self::Subtrait(_) | Self::StructuralTrait(_) => Type::TraitType,
|
||||||
|
Self::Patch(_) => Type::Patch,
|
||||||
_ => Type::Type,
|
_ => Type::Type,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -230,6 +256,7 @@ impl GenTypeObj {
|
||||||
Self::Subtrait(subtrait) => &subtrait.t,
|
Self::Subtrait(subtrait) => &subtrait.t,
|
||||||
Self::StructuralTrait(trait_) => &trait_.t,
|
Self::StructuralTrait(trait_) => &trait_.t,
|
||||||
Self::Union(union_) => &union_.t,
|
Self::Union(union_) => &union_.t,
|
||||||
|
Self::Patch(patch) => &patch.t,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,6 +268,7 @@ impl GenTypeObj {
|
||||||
Self::Subtrait(subtrait) => &mut subtrait.t,
|
Self::Subtrait(subtrait) => &mut subtrait.t,
|
||||||
Self::StructuralTrait(trait_) => &mut trait_.t,
|
Self::StructuralTrait(trait_) => &mut trait_.t,
|
||||||
Self::Union(union_) => &mut union_.t,
|
Self::Union(union_) => &mut union_.t,
|
||||||
|
Self::Patch(patch) => &mut patch.t,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,6 +280,7 @@ impl GenTypeObj {
|
||||||
Self::Subtrait(subtrait) => subtrait.t,
|
Self::Subtrait(subtrait) => subtrait.t,
|
||||||
Self::StructuralTrait(trait_) => trait_.t,
|
Self::StructuralTrait(trait_) => trait_.t,
|
||||||
Self::Union(union_) => union_.t,
|
Self::Union(union_) => union_.t,
|
||||||
|
Self::Patch(patch) => patch.t,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3412,6 +3412,36 @@ impl ClassDef {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct PatchDef {
|
||||||
|
pub def: Def,
|
||||||
|
pub methods_list: Vec<Methods>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NestedDisplay for PatchDef {
|
||||||
|
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result {
|
||||||
|
write!(f, "(patch)")?;
|
||||||
|
self.def.fmt_nest(f, level)?;
|
||||||
|
for methods in self.methods_list.iter() {
|
||||||
|
write!(f, "(methods)")?;
|
||||||
|
methods.fmt_nest(f, level + 1)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_display_from_nested!(PatchDef);
|
||||||
|
impl_locational!(PatchDef, def);
|
||||||
|
|
||||||
|
impl PatchDef {
|
||||||
|
pub const fn new(def: Def, methods: Vec<Methods>) -> Self {
|
||||||
|
Self {
|
||||||
|
def,
|
||||||
|
methods_list: methods,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Expression(式)
|
/// Expression(式)
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub enum Expr {
|
pub enum Expr {
|
||||||
|
@ -3431,11 +3461,12 @@ pub enum Expr {
|
||||||
Def(Def),
|
Def(Def),
|
||||||
Methods(Methods),
|
Methods(Methods),
|
||||||
ClassDef(ClassDef),
|
ClassDef(ClassDef),
|
||||||
|
PatchDef(PatchDef),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_nested_display_for_chunk_enum!(Expr; Lit, Accessor, Array, Tuple, Dict, Set, Record, BinOp, UnaryOp, Call, DataPack, Lambda, TypeAsc, Def, Methods, ClassDef);
|
impl_nested_display_for_chunk_enum!(Expr; Lit, Accessor, Array, Tuple, Dict, Set, Record, BinOp, UnaryOp, Call, DataPack, Lambda, TypeAsc, Def, Methods, ClassDef, PatchDef);
|
||||||
impl_display_from_nested!(Expr);
|
impl_display_from_nested!(Expr);
|
||||||
impl_locational_for_enum!(Expr; Lit, Accessor, Array, Tuple, Dict, Set, Record, BinOp, UnaryOp, Call, DataPack, Lambda, TypeAsc, Def, Methods, ClassDef);
|
impl_locational_for_enum!(Expr; Lit, Accessor, Array, Tuple, Dict, Set, Record, BinOp, UnaryOp, Call, DataPack, Lambda, TypeAsc, Def, Methods, ClassDef, PatchDef);
|
||||||
|
|
||||||
impl Expr {
|
impl Expr {
|
||||||
pub fn is_match_call(&self) -> bool {
|
pub fn is_match_call(&self) -> bool {
|
||||||
|
@ -3451,7 +3482,10 @@ impl Expr {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn is_definition(&self) -> bool {
|
pub const fn is_definition(&self) -> bool {
|
||||||
matches!(self, Expr::Def(_) | Expr::ClassDef(_) | Expr::Methods(_))
|
matches!(
|
||||||
|
self,
|
||||||
|
Expr::Def(_) | Expr::ClassDef(_) | Expr::PatchDef(_) | Expr::Methods(_)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn need_to_be_closed(&self) -> bool {
|
pub fn need_to_be_closed(&self) -> bool {
|
||||||
|
|
|
@ -16,9 +16,10 @@ use crate::ast::{
|
||||||
ClassAttr, ClassAttrs, ClassDef, ConstExpr, DataPack, Def, DefBody, DefId, Dict, Expr,
|
ClassAttr, ClassAttrs, ClassDef, ConstExpr, DataPack, Def, DefBody, DefId, Dict, Expr,
|
||||||
Identifier, KeyValue, KwArg, Lambda, LambdaSignature, Literal, Methods, MixedRecord, Module,
|
Identifier, KeyValue, KwArg, Lambda, LambdaSignature, Literal, Methods, MixedRecord, Module,
|
||||||
NonDefaultParamSignature, NormalArray, NormalDict, NormalRecord, NormalSet, NormalTuple,
|
NonDefaultParamSignature, NormalArray, NormalDict, NormalRecord, NormalSet, NormalTuple,
|
||||||
ParamPattern, ParamRecordAttr, Params, PosArg, Record, RecordAttrOrIdent, RecordAttrs,
|
ParamPattern, ParamRecordAttr, Params, PatchDef, PosArg, Record, RecordAttrOrIdent,
|
||||||
Set as astSet, SetWithLength, Signature, SubrSignature, Tuple, TypeAppArgs, TypeBoundSpecs,
|
RecordAttrs, Set as astSet, SetWithLength, Signature, SubrSignature, Tuple, TypeAppArgs,
|
||||||
TypeSpec, TypeSpecWithOp, UnaryOp, VarName, VarPattern, VarRecordAttr, VarSignature,
|
TypeBoundSpecs, TypeSpec, TypeSpecWithOp, UnaryOp, VarName, VarPattern, VarRecordAttr,
|
||||||
|
VarSignature,
|
||||||
};
|
};
|
||||||
use crate::token::{Token, TokenKind, COLON, DOT};
|
use crate::token::{Token, TokenKind, COLON, DOT};
|
||||||
|
|
||||||
|
@ -225,6 +226,15 @@ impl Desugarer {
|
||||||
.collect();
|
.collect();
|
||||||
Expr::ClassDef(ClassDef::new(def, methods))
|
Expr::ClassDef(ClassDef::new(def, methods))
|
||||||
}
|
}
|
||||||
|
Expr::PatchDef(class_def) => {
|
||||||
|
let def = enum_unwrap!(desugar(Expr::Def(class_def.def)), Expr::Def);
|
||||||
|
let methods = class_def
|
||||||
|
.methods_list
|
||||||
|
.into_iter()
|
||||||
|
.map(|method| enum_unwrap!(desugar(Expr::Methods(method)), Expr::Methods))
|
||||||
|
.collect();
|
||||||
|
Expr::PatchDef(PatchDef::new(def, methods))
|
||||||
|
}
|
||||||
Expr::Lambda(lambda) => {
|
Expr::Lambda(lambda) => {
|
||||||
let mut chunks = vec![];
|
let mut chunks = vec![];
|
||||||
for chunk in lambda.body.into_iter() {
|
for chunk in lambda.body.into_iter() {
|
||||||
|
|
|
@ -34,7 +34,7 @@ StrangeInt.
|
||||||
# Overriding methods must be given Override decorators.
|
# Overriding methods must be given Override decorators.
|
||||||
# In addition, you need to override all Int methods that depend on Int.`_+_`.
|
# In addition, you need to override all Int methods that depend on Int.`_+_`.
|
||||||
@Override
|
@Override
|
||||||
`_+_` = Super.`_-_` # OverrideError: Int.`_+_` is referenced by ... ````` , so these methods must also be overridden
|
`_+_` = Super.`_-_` # OverrideError: Int.`_+_` is referenced by ... , so these methods must also be overridden
|
||||||
```
|
```
|
||||||
|
|
||||||
## Selecting Patches
|
## Selecting Patches
|
||||||
|
|
|
@ -14,23 +14,14 @@ namedtupleについては、[こちら](https://docs.python.jp/3/library/collect
|
||||||
似たような機能にdataclassがありますが、dataclassは`__eq__`や`__hash__`が自動実装されるなどの影響で少しパフォーマンスが落ちます。
|
似たような機能にdataclassがありますが、dataclassは`__eq__`や`__hash__`が自動実装されるなどの影響で少しパフォーマンスが落ちます。
|
||||||
|
|
||||||
```python
|
```python
|
||||||
Employee = Class {.name = Str; .id = Int}
|
employee = {.name = "John Smith"; .id = 100}
|
||||||
|
|
||||||
employee = Employee.new({.name = "John Smith"; .id = 100})
|
|
||||||
|
|
||||||
assert employee.name == "John Smith"
|
assert employee.name == "John Smith"
|
||||||
```
|
```
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from typing import NamedTuple
|
from typing import NamedTuple
|
||||||
|
|
||||||
class Employee(NamedTuple):
|
employee = NamedTuple(['name', 'id'])('John Smith', 100)
|
||||||
__records__ = ['name', 'id']
|
|
||||||
name: str
|
|
||||||
id: int
|
|
||||||
|
|
||||||
employee = Employee('John Smith', 100)
|
|
||||||
|
|
||||||
assert employee.name == 'John Smith'
|
assert employee.name == 'John Smith'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -90,3 +81,19 @@ y::x = 2
|
||||||
assert module::x == 2
|
assert module::x == 2
|
||||||
y = None
|
y = None
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Patch
|
||||||
|
|
||||||
|
```python
|
||||||
|
func b: Bool =
|
||||||
|
Invert = Patch Bool
|
||||||
|
Invert.
|
||||||
|
invert self = not self
|
||||||
|
b.invert()
|
||||||
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
def func(b):
|
||||||
|
def Invert::invert(self): return not self
|
||||||
|
return Invert::invert(b)
|
||||||
|
```
|
||||||
|
|
|
@ -1,12 +1,20 @@
|
||||||
Binary = Patch {0, 1}
|
Invert = Patch Bool
|
||||||
Binary.
|
Invert::
|
||||||
invert self =
|
_zero = False
|
||||||
if self == 0, 1 else 0
|
_invert self = not self
|
||||||
assert 1.invert() == 0
|
Invert.
|
||||||
assert 0.invert() == 1
|
zero = Invert::_zero
|
||||||
|
invert self = self::_invert()
|
||||||
|
|
||||||
Nat = Patch {I | I >= 0}
|
assert False.invert()
|
||||||
Nat.times! self, block! =
|
|
||||||
for! 0..<self, _ => block!()
|
.ToLower = Patch Str
|
||||||
10.times! do!:
|
.ToLower::
|
||||||
print! "!"
|
_lowers = "abcdefghijklmnopqrstuvwxyz"
|
||||||
|
_to_lowercase self = self.lower()
|
||||||
|
.ToLower.
|
||||||
|
lowers = .ToLower::_lowers
|
||||||
|
to_lowercase self = self::_to_lowercase()
|
||||||
|
|
||||||
|
print! "".lowers
|
||||||
|
print! "AAA".to_lowercase()
|
||||||
|
|
|
@ -84,6 +84,11 @@ fn exec_infer_trait() -> Result<(), ()> {
|
||||||
expect_success("tests/should_ok/infer_trait.er")
|
expect_success("tests/should_ok/infer_trait.er")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn exec_patch() -> Result<(), ()> {
|
||||||
|
expect_success("examples/patch.er")
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn exec_pattern() -> Result<(), ()> {
|
fn exec_pattern() -> Result<(), ()> {
|
||||||
expect_success("tests/should_ok/pattern.er")
|
expect_success("tests/should_ok/pattern.er")
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue