feat: add Dict.concat/diff, Dict!.merge!/remove!

This commit is contained in:
Shunsuke Shibayama 2023-10-04 22:39:30 +09:00
parent 73958a3e56
commit 13a346e488
11 changed files with 223 additions and 6 deletions

View file

@ -1798,6 +1798,40 @@ impl Context {
dict_.register_py_builtin(FUNC_GET, get_t, Some(FUNC_GET), 9);
let copy_t = fn0_met(dict_t.clone(), dict_t.clone()).quantify();
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 */
let mut bytes = Self::builtin_mono_class(BYTES, 2);
bytes.register_superclass(Obj, &obj);
@ -2692,16 +2726,66 @@ impl Context {
dict_mut_t.clone(),
Some(poly(
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,
vec![],
NoneType,
)
.quantify();
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! */
let set_mut_t = poly(MUT_SET, vec![ty_tp(T.clone()), N]);
let mut set_mut_ =

View file

@ -363,6 +363,32 @@ pub(crate) fn dict_items(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<
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`
pub(crate) fn array_union(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<TyParam> {
let slf = args

View file

@ -54,6 +54,7 @@ const SELF: &str = "Self";
const IMMUTIZABLE: &str = "Immutizable";
const IMMUT_TYPE: &str = "ImmutType";
const PROC_UPDATE: &str = "update!";
const FUNC_UPDATE: &str = "update";
const MUTIZABLE: &str = "Mutizable";
const MUTABLE_MUT_TYPE: &str = "MutType!";
const PATH_LIKE: &str = "PathLike";
@ -232,8 +233,11 @@ const PROC_UPDATE_NTH: &str = "update_nth!";
const FUNC_PARTITION: &str = "partition";
const FUNC_DEDUP: &str = "dedup";
const FUNC_CONCAT: &str = "concat";
const FUNC_DIFF: &str = "diff";
const FUNC_PUSH: &str = "push";
const PROC_PUSH: &str = "push!";
const FUNC_MERGE: &str = "merge";
const PROC_MERGE: &str = "merge!";
const ARRAY_ITERATOR: &str = "ArrayIterator";
const GENERIC_SET: &str = "GenericSet";
const SET: &str = "Set";
@ -557,6 +561,7 @@ const KW_SUB: &str = "sub";
const KW_OFFSET: &str = "offset";
const KW_WHENCE: &str = "whence";
const KW_CHARS: &str = "chars";
const KW_OTHER: &str = "other";
pub fn builtins_path() -> PathBuf {
erg_pystd_path().join("builtins.d.er")