mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-28 04:09:05 +00:00
feat: add Dict.concat/diff
, Dict!.merge!/remove!
This commit is contained in:
parent
73958a3e56
commit
13a346e488
11 changed files with 223 additions and 6 deletions
|
@ -1304,6 +1304,32 @@ impl Context {
|
||||||
(e @ TyParam::Erased(_), _) | (_, e @ TyParam::Erased(_)) => Ok(e),
|
(e @ TyParam::Erased(_), _) | (_, e @ TyParam::Erased(_)) => Ok(e),
|
||||||
(lhs @ TyParam::FreeVar(_), rhs) => Ok(TyParam::bin(op, lhs, rhs)),
|
(lhs @ TyParam::FreeVar(_), rhs) => Ok(TyParam::bin(op, lhs, rhs)),
|
||||||
(lhs, rhs @ TyParam::FreeVar(_)) => Ok(TyParam::bin(op, lhs, rhs)),
|
(lhs, rhs @ TyParam::FreeVar(_)) => Ok(TyParam::bin(op, lhs, rhs)),
|
||||||
|
(TyParam::Value(lhs), rhs) => {
|
||||||
|
let lhs = match Self::convert_value_into_tp(lhs) {
|
||||||
|
Ok(tp) => tp,
|
||||||
|
Err(lhs) => {
|
||||||
|
return feature_error!(
|
||||||
|
self,
|
||||||
|
Location::Unknown,
|
||||||
|
&format!("{lhs} {op} {rhs}")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
self.eval_bin_tp(op, lhs, rhs)
|
||||||
|
}
|
||||||
|
(lhs, TyParam::Value(rhs)) => {
|
||||||
|
let rhs = match Self::convert_value_into_tp(rhs) {
|
||||||
|
Ok(tp) => tp,
|
||||||
|
Err(rhs) => {
|
||||||
|
return feature_error!(
|
||||||
|
self,
|
||||||
|
Location::Unknown,
|
||||||
|
&format!("{lhs} {op} {rhs}")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
self.eval_bin_tp(op, lhs, rhs)
|
||||||
|
}
|
||||||
(l, r) => feature_error!(self, Location::Unknown, &format!("{l} {op} {r}"))
|
(l, r) => feature_error!(self, Location::Unknown, &format!("{l} {op} {r}"))
|
||||||
.map_err(Into::into),
|
.map_err(Into::into),
|
||||||
}
|
}
|
||||||
|
@ -1439,6 +1465,10 @@ impl Context {
|
||||||
}
|
}
|
||||||
Ok(TyParam::Array(new_tps))
|
Ok(TyParam::Array(new_tps))
|
||||||
}
|
}
|
||||||
|
TyParam::UnsizedArray(elem) => {
|
||||||
|
let elem = self.eval_tp(*elem)?;
|
||||||
|
Ok(TyParam::UnsizedArray(Box::new(elem)))
|
||||||
|
}
|
||||||
TyParam::Tuple(tps) => {
|
TyParam::Tuple(tps) => {
|
||||||
let mut new_tps = Vec::with_capacity(tps.len());
|
let mut new_tps = Vec::with_capacity(tps.len());
|
||||||
for tp in tps {
|
for tp in tps {
|
||||||
|
@ -1484,7 +1514,7 @@ impl Context {
|
||||||
}
|
}
|
||||||
TyParam::ProjCall { obj, attr, args } => self.eval_proj_call(*obj, attr, args, &()),
|
TyParam::ProjCall { obj, attr, args } => self.eval_proj_call(*obj, attr, args, &()),
|
||||||
TyParam::Value(_) => Ok(p.clone()),
|
TyParam::Value(_) => Ok(p.clone()),
|
||||||
_other => feature_error!(self, Location::Unknown, "???"),
|
other => feature_error!(self, Location::Unknown, &format!("evaluating {other}")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1798,6 +1798,40 @@ impl Context {
|
||||||
dict_.register_py_builtin(FUNC_GET, get_t, Some(FUNC_GET), 9);
|
dict_.register_py_builtin(FUNC_GET, get_t, Some(FUNC_GET), 9);
|
||||||
let copy_t = fn0_met(dict_t.clone(), dict_t.clone()).quantify();
|
let copy_t = fn0_met(dict_t.clone(), dict_t.clone()).quantify();
|
||||||
dict_.register_py_builtin(COPY, copy_t, Some(COPY), 7);
|
dict_.register_py_builtin(COPY, copy_t, Some(COPY), 7);
|
||||||
|
let D2 = mono_q_tp("D2", instanceof(mono(GENERIC_DICT)));
|
||||||
|
let other_dict_t = poly(DICT, vec![D2.clone()]);
|
||||||
|
let dict_concat_t = fn1_met(
|
||||||
|
dict_t.clone(),
|
||||||
|
other_dict_t.clone(),
|
||||||
|
poly(
|
||||||
|
DICT,
|
||||||
|
vec![D.clone().proj_call(FUNC_CONCAT.into(), vec![D2.clone()])],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.quantify();
|
||||||
|
let concat = ValueObj::Subr(ConstSubr::Builtin(BuiltinConstSubr::new(
|
||||||
|
FUNC_CONCAT,
|
||||||
|
dict_concat,
|
||||||
|
dict_concat_t,
|
||||||
|
None,
|
||||||
|
)));
|
||||||
|
dict_.register_builtin_const(FUNC_CONCAT, Visibility::BUILTIN_PUBLIC, concat);
|
||||||
|
let dict_diff_t = fn1_met(
|
||||||
|
dict_t.clone(),
|
||||||
|
other_dict_t.clone(),
|
||||||
|
poly(
|
||||||
|
DICT,
|
||||||
|
vec![D.clone().proj_call(FUNC_DIFF.into(), vec![D2.clone()])],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.quantify();
|
||||||
|
let diff = ValueObj::Subr(ConstSubr::Builtin(BuiltinConstSubr::new(
|
||||||
|
FUNC_DIFF,
|
||||||
|
dict_diff,
|
||||||
|
dict_diff_t,
|
||||||
|
None,
|
||||||
|
)));
|
||||||
|
dict_.register_builtin_const(FUNC_DIFF, Visibility::BUILTIN_PUBLIC, diff);
|
||||||
/* Bytes */
|
/* Bytes */
|
||||||
let mut bytes = Self::builtin_mono_class(BYTES, 2);
|
let mut bytes = Self::builtin_mono_class(BYTES, 2);
|
||||||
bytes.register_superclass(Obj, &obj);
|
bytes.register_superclass(Obj, &obj);
|
||||||
|
@ -2692,16 +2726,66 @@ impl Context {
|
||||||
dict_mut_t.clone(),
|
dict_mut_t.clone(),
|
||||||
Some(poly(
|
Some(poly(
|
||||||
MUT_DICT,
|
MUT_DICT,
|
||||||
vec![D + dict! { K.clone() => V.clone() }.into()],
|
vec![D.clone() + dict! { K.clone() => V.clone() }.into()],
|
||||||
)),
|
)),
|
||||||
),
|
),
|
||||||
vec![kw(KW_KEY, K), kw(KW_VALUE, V)],
|
vec![kw(KW_KEY, K.clone()), kw(KW_VALUE, V.clone())],
|
||||||
None,
|
None,
|
||||||
vec![],
|
vec![],
|
||||||
NoneType,
|
NoneType,
|
||||||
)
|
)
|
||||||
.quantify();
|
.quantify();
|
||||||
dict_mut.register_py_builtin(PROC_INSERT, insert_t, Some(FUNDAMENTAL_SETITEM), 12);
|
dict_mut.register_py_builtin(PROC_INSERT, insert_t, Some(FUNDAMENTAL_SETITEM), 12);
|
||||||
|
let remove_t = pr_met(
|
||||||
|
ref_mut(
|
||||||
|
dict_mut_t.clone(),
|
||||||
|
Some(poly(
|
||||||
|
MUT_DICT,
|
||||||
|
vec![D
|
||||||
|
.clone()
|
||||||
|
.proj_call(FUNC_DIFF.into(), vec![dict! { K.clone() => Never }.into()])],
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
vec![kw(KW_KEY, K.clone())],
|
||||||
|
None,
|
||||||
|
vec![],
|
||||||
|
proj_call(D.clone(), FUNDAMENTAL_GETITEM, vec![ty_tp(K.clone())]) | NoneType,
|
||||||
|
)
|
||||||
|
.quantify();
|
||||||
|
dict_mut.register_py_builtin(PROC_REMOVE, remove_t, Some(FUNC_REMOVE), 19);
|
||||||
|
let update_t = pr_met(
|
||||||
|
ref_mut(
|
||||||
|
dict_mut_t.clone(),
|
||||||
|
Some(poly(
|
||||||
|
MUT_DICT,
|
||||||
|
vec![D.clone() + dict! { K.clone() => V.clone() }.into()],
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
vec![kw(
|
||||||
|
KW_ITERABLE,
|
||||||
|
poly(ITERABLE, vec![ty_tp(tuple_t(vec![K.clone(), V.clone()]))]),
|
||||||
|
)],
|
||||||
|
None,
|
||||||
|
vec![],
|
||||||
|
NoneType,
|
||||||
|
)
|
||||||
|
.quantify();
|
||||||
|
dict_mut.register_py_builtin(PROC_UPDATE, update_t, Some(FUNC_UPDATE), 26);
|
||||||
|
let merge_t = pr_met(
|
||||||
|
ref_mut(
|
||||||
|
dict_mut_t.clone(),
|
||||||
|
Some(poly(
|
||||||
|
MUT_DICT,
|
||||||
|
vec![D.proj_call(FUNC_CONCAT.into(), vec![D2.clone()])],
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
vec![kw(KW_OTHER, poly(DICT, vec![D2.clone()]))],
|
||||||
|
None,
|
||||||
|
vec![],
|
||||||
|
NoneType,
|
||||||
|
)
|
||||||
|
.quantify();
|
||||||
|
dict_mut.register_py_builtin(PROC_MERGE, merge_t, Some(FUNC_MERGE), 32);
|
||||||
/* Set! */
|
/* Set! */
|
||||||
let set_mut_t = poly(MUT_SET, vec![ty_tp(T.clone()), N]);
|
let set_mut_t = poly(MUT_SET, vec![ty_tp(T.clone()), N]);
|
||||||
let mut set_mut_ =
|
let mut set_mut_ =
|
||||||
|
|
|
@ -363,6 +363,32 @@ pub(crate) fn dict_items(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<
|
||||||
Ok(ValueObj::builtin_type(union).into())
|
Ok(ValueObj::builtin_type(union).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If the key is duplicated, the value of the right dict is used.
|
||||||
|
/// `{Str: Int, Int: Float}.concat({Int: Str, Float: Bool}) == {Str: Int, Int: Str, Float: Bool}`
|
||||||
|
pub(crate) fn dict_concat(mut args: ValueArgs, _ctx: &Context) -> EvalValueResult<TyParam> {
|
||||||
|
let slf = args
|
||||||
|
.remove_left_or_key("Self")
|
||||||
|
.ok_or_else(|| not_passed("Self"))?;
|
||||||
|
let slf = enum_unwrap!(slf, ValueObj::Dict);
|
||||||
|
let other = args
|
||||||
|
.remove_left_or_key("Other")
|
||||||
|
.ok_or_else(|| not_passed("Other"))?;
|
||||||
|
let other = enum_unwrap!(other, ValueObj::Dict);
|
||||||
|
Ok(ValueObj::Dict(slf.concat(other)).into())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn dict_diff(mut args: ValueArgs, _ctx: &Context) -> EvalValueResult<TyParam> {
|
||||||
|
let slf = args
|
||||||
|
.remove_left_or_key("Self")
|
||||||
|
.ok_or_else(|| not_passed("Self"))?;
|
||||||
|
let slf = enum_unwrap!(slf, ValueObj::Dict);
|
||||||
|
let other = args
|
||||||
|
.remove_left_or_key("Other")
|
||||||
|
.ok_or_else(|| not_passed("Other"))?;
|
||||||
|
let other = enum_unwrap!(other, ValueObj::Dict);
|
||||||
|
Ok(ValueObj::Dict(slf.diff(&other)).into())
|
||||||
|
}
|
||||||
|
|
||||||
/// `[Int, Str].union() == Int or Str`
|
/// `[Int, Str].union() == Int or Str`
|
||||||
pub(crate) fn array_union(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<TyParam> {
|
pub(crate) fn array_union(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<TyParam> {
|
||||||
let slf = args
|
let slf = args
|
||||||
|
|
|
@ -54,6 +54,7 @@ const SELF: &str = "Self";
|
||||||
const IMMUTIZABLE: &str = "Immutizable";
|
const IMMUTIZABLE: &str = "Immutizable";
|
||||||
const IMMUT_TYPE: &str = "ImmutType";
|
const IMMUT_TYPE: &str = "ImmutType";
|
||||||
const PROC_UPDATE: &str = "update!";
|
const PROC_UPDATE: &str = "update!";
|
||||||
|
const FUNC_UPDATE: &str = "update";
|
||||||
const MUTIZABLE: &str = "Mutizable";
|
const MUTIZABLE: &str = "Mutizable";
|
||||||
const MUTABLE_MUT_TYPE: &str = "MutType!";
|
const MUTABLE_MUT_TYPE: &str = "MutType!";
|
||||||
const PATH_LIKE: &str = "PathLike";
|
const PATH_LIKE: &str = "PathLike";
|
||||||
|
@ -232,8 +233,11 @@ const PROC_UPDATE_NTH: &str = "update_nth!";
|
||||||
const FUNC_PARTITION: &str = "partition";
|
const FUNC_PARTITION: &str = "partition";
|
||||||
const FUNC_DEDUP: &str = "dedup";
|
const FUNC_DEDUP: &str = "dedup";
|
||||||
const FUNC_CONCAT: &str = "concat";
|
const FUNC_CONCAT: &str = "concat";
|
||||||
|
const FUNC_DIFF: &str = "diff";
|
||||||
const FUNC_PUSH: &str = "push";
|
const FUNC_PUSH: &str = "push";
|
||||||
const PROC_PUSH: &str = "push!";
|
const PROC_PUSH: &str = "push!";
|
||||||
|
const FUNC_MERGE: &str = "merge";
|
||||||
|
const PROC_MERGE: &str = "merge!";
|
||||||
const ARRAY_ITERATOR: &str = "ArrayIterator";
|
const ARRAY_ITERATOR: &str = "ArrayIterator";
|
||||||
const GENERIC_SET: &str = "GenericSet";
|
const GENERIC_SET: &str = "GenericSet";
|
||||||
const SET: &str = "Set";
|
const SET: &str = "Set";
|
||||||
|
@ -557,6 +561,7 @@ const KW_SUB: &str = "sub";
|
||||||
const KW_OFFSET: &str = "offset";
|
const KW_OFFSET: &str = "offset";
|
||||||
const KW_WHENCE: &str = "whence";
|
const KW_WHENCE: &str = "whence";
|
||||||
const KW_CHARS: &str = "chars";
|
const KW_CHARS: &str = "chars";
|
||||||
|
const KW_OTHER: &str = "other";
|
||||||
|
|
||||||
pub fn builtins_path() -> PathBuf {
|
pub fn builtins_path() -> PathBuf {
|
||||||
erg_pystd_path().join("builtins.d.er")
|
erg_pystd_path().join("builtins.d.er")
|
||||||
|
|
|
@ -4,4 +4,29 @@ dict = pyimport "Dict"
|
||||||
.Dict!: ClassType
|
.Dict!: ClassType
|
||||||
.Dict! <: dict.Dict
|
.Dict! <: dict.Dict
|
||||||
.Dict!.
|
.Dict!.
|
||||||
insert!: |K, V|(self: .Dict!, key: K, value: V) => NoneType
|
'''erg
|
||||||
|
dic = !{"a": 1}
|
||||||
|
dic.insert!("b", 2)
|
||||||
|
assert dic == {"a": 1, "b": 2}
|
||||||
|
'''
|
||||||
|
insert!: |K, V|(self: .Dict!(K, V), key: K, value: V) => NoneType
|
||||||
|
'''erg
|
||||||
|
dic = !{"a": 1}
|
||||||
|
x = dic.remove!("a")
|
||||||
|
assert dic == {}
|
||||||
|
assert x == 1
|
||||||
|
'''
|
||||||
|
remove!: |K, V|(self: .Dict!(K, V), key: K) => V or NoneType
|
||||||
|
'''erg
|
||||||
|
dic = !{"a": 1}
|
||||||
|
dic.update!({"b": 2})
|
||||||
|
dic.update!([("c", 3)])
|
||||||
|
assert dic == {"a": 1, "b": 2, "c": 3}
|
||||||
|
'''
|
||||||
|
update!: |K, V|(self: .Dict!(K, V), other: Iterable([K, V])) => NoneType
|
||||||
|
'''erg
|
||||||
|
dic = !{"a": 1}
|
||||||
|
dic.merge!({"b": 2})
|
||||||
|
assert dic == {"a": 1, "b": 2}
|
||||||
|
'''
|
||||||
|
merge!: |K, V|(self: .Dict!(K, V), other: .Dict!(K, V)) => NoneType
|
||||||
|
|
|
@ -10,3 +10,13 @@
|
||||||
items: |K, V|(self: .Dict(K, V)) -> .DictItems(K, V)
|
items: |K, V|(self: .Dict(K, V)) -> .DictItems(K, V)
|
||||||
keys: |K, V|(self: .Dict(K, V)) -> .DictKeys(K, V)
|
keys: |K, V|(self: .Dict(K, V)) -> .DictKeys(K, V)
|
||||||
values: |K, V|(self: .Dict(K, V)) -> .DictValues(K, V)
|
values: |K, V|(self: .Dict(K, V)) -> .DictValues(K, V)
|
||||||
|
'''erg
|
||||||
|
dic = {"a": 1, "b": 2}
|
||||||
|
assert dic.concat({"c": 3}) == {"a": 1, "b": 2, "c": 3}
|
||||||
|
'''
|
||||||
|
concat: (self: .Dict(K, V), other: .Dict(K, V)) -> .Dict(K, V)
|
||||||
|
'''erg
|
||||||
|
dic = {"a": 1, "b": 2}
|
||||||
|
assert dic.diff({"a": 2, "d": 4}) == {"b": 2}
|
||||||
|
'''
|
||||||
|
diff: (self: .Dict(K, V), other: .Dict(K, V)) -> .Dict(K, V)
|
||||||
|
|
|
@ -1,2 +1,18 @@
|
||||||
class Dict(dict):
|
class Dict(dict):
|
||||||
pass
|
def concat(self, other):
|
||||||
|
return Dict({**self, **other})
|
||||||
|
def diff(self, other):
|
||||||
|
return Dict({k: v for k, v in self.items() if k not in other})
|
||||||
|
# other: Iterable
|
||||||
|
def extend(self, other):
|
||||||
|
self.update(other)
|
||||||
|
# other: Dict
|
||||||
|
def merge(self, other):
|
||||||
|
self.update(other)
|
||||||
|
def insert(self, key, value):
|
||||||
|
self[key] = value
|
||||||
|
def remove(self, key):
|
||||||
|
res = self.get(key)
|
||||||
|
if res != None:
|
||||||
|
del self[key]
|
||||||
|
return res
|
||||||
|
|
|
@ -1363,6 +1363,15 @@ impl TyParam {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_type(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::Type(_) => true,
|
||||||
|
Self::FreeVar(fv) if fv.is_linked() => fv.crack().is_type(),
|
||||||
|
Self::Value(ValueObj::Type(_)) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn replace(self, target: &Type, to: &Type) -> TyParam {
|
pub fn replace(self, target: &Type, to: &Type) -> TyParam {
|
||||||
match self {
|
match self {
|
||||||
TyParam::Value(ValueObj::Type(obj)) => {
|
TyParam::Value(ValueObj::Type(obj)) => {
|
||||||
|
|
|
@ -494,7 +494,7 @@ impl TypeObj {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 値オブジェクト
|
/// 値オブジェクト
|
||||||
/// コンパイル時評価ができ、シリアライズも可能
|
/// コンパイル時評価ができ、シリアライズも可能(Typeなどはシリアライズ不可)
|
||||||
#[derive(Clone, PartialEq, Default)]
|
#[derive(Clone, PartialEq, Default)]
|
||||||
pub enum ValueObj {
|
pub enum ValueObj {
|
||||||
Int(i32),
|
Int(i32),
|
||||||
|
|
|
@ -2,3 +2,7 @@ for! {"a": 1, "b": 2}.keys(), s =>
|
||||||
print! "key: " + s
|
print! "key: " + s
|
||||||
for! {"a": 1, "b": 2}.values(), i =>
|
for! {"a": 1, "b": 2}.values(), i =>
|
||||||
print! i + 0
|
print! i + 0
|
||||||
|
|
||||||
|
dic = { "a": 1, "b": 2 }
|
||||||
|
assert dic.concat({ "c": 3 }) == { "a": 1, "b": 2, "c": 3 }
|
||||||
|
assert dic.diff({ "a": 1 }) == { "b": 2 }
|
||||||
|
|
|
@ -4,3 +4,11 @@ dic = !d
|
||||||
dic.insert! "b", 2
|
dic.insert! "b", 2
|
||||||
assert dic.get("a") == 1
|
assert dic.get("a") == 1
|
||||||
assert dic.get("b") == 2
|
assert dic.get("b") == 2
|
||||||
|
|
||||||
|
dic.merge!({ "a": 1 })
|
||||||
|
x = dic.remove!("a")
|
||||||
|
assert x == 1
|
||||||
|
|
||||||
|
dics as Dict!({Str: [Int; _]}) = !{:}
|
||||||
|
dics.insert! "a", []
|
||||||
|
dics.insert! "b", [1, 2, 3]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue