feat: add Record.as_dict()

This commit is contained in:
Shunsuke Shibayama 2023-08-20 02:02:53 +09:00
parent 2966497ad6
commit 5e71bd7fd0
6 changed files with 96 additions and 4 deletions

View file

@ -1808,6 +1808,21 @@ impl Context {
Visibility::BUILTIN_PUBLIC,
);
record.register_trait(mono(RECORD), record_eq);
let Slf = mono_q("Self", subtypeof(mono(RECORD)));
let into_dict_t =
fn0_met(Slf.clone(), proj_call(ty_tp(Slf), FUNC_AS_DICT, vec![])).quantify();
let into_dict = ValueObj::Subr(ConstSubr::Builtin(BuiltinConstSubr::new(
FUNC_UNION,
as_dict,
into_dict_t,
None,
)));
record.register_py_builtin_const(
FUNC_AS_DICT,
Visibility::BUILTIN_PUBLIC,
into_dict,
Some("_asdict"),
);
/* GenericNamedTuple */
let mut generic_named_tuple = Self::builtin_mono_class(GENERIC_NAMED_TUPLE, 2);
generic_named_tuple.register_superclass(mono(GENERIC_TUPLE), &generic_tuple);

View file

@ -2,13 +2,13 @@ use std::fmt::Display;
use std::mem;
use erg_common::dict::Dict;
use erg_common::enum_unwrap;
#[allow(unused_imports)]
use erg_common::log;
use erg_common::{enum_unwrap, set};
use crate::context::Context;
use crate::feature_error;
use crate::ty::constructors::{and, mono, poly, tuple_t, ty_tp};
use crate::ty::constructors::{and, mono, poly, tuple_t, ty_tp, v_enum};
use crate::ty::value::{EvalValueError, EvalValueResult, GenTypeObj, TypeObj, ValueObj};
use crate::ty::{TyParam, Type, ValueArgs};
use erg_common::error::{ErrorCore, ErrorKind, Location, SubMessage};
@ -499,3 +499,24 @@ pub(crate) fn named_tuple_union(mut args: ValueArgs, ctx: &Context) -> EvalValue
.fold(Type::Never, |union, (_, t)| ctx.union(&union, t));
Ok(ValueObj::builtin_type(union).into())
}
/// `{ .x = Int; .y = Str }.as_dict() == { "x": Int, "y": Str }`
pub(crate) fn as_dict(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<TyParam> {
let slf = args
.remove_left_or_key("Self")
.ok_or_else(|| not_passed("Self"))?;
let fields = match ctx.convert_value_into_type(slf) {
Ok(Type::Record(fields)) => fields,
Ok(other) => {
return Err(type_mismatch("Record", other, "Self"));
}
Err(val) => {
return Err(type_mismatch("Record", val, "Self"));
}
};
let dict = fields
.into_iter()
.map(|(k, v)| (v_enum(set! { k.symbol.into() }), v))
.collect::<Dict<_, _>>();
Ok(ValueObj::builtin_type(Type::from(dict)).into())
}

View file

@ -263,6 +263,7 @@ const SYMMETRIC_DIFFERENCE: &str = "symmetric_difference";
const MEMORYVIEW: &str = "MemoryView";
const FUNC_UNION: &str = "union";
const FUNC_SHAPE: &str = "shape";
const FUNC_AS_DICT: &str = "as_dict";
const FUNC_INC: &str = "inc";
const PROC_INC: &str = "inc!";
const FUNC_DEC: &str = "dec";
@ -721,6 +722,37 @@ impl Context {
}
}
fn register_py_builtin_const(
&mut self,
name: &str,
vis: Visibility,
obj: ValueObj,
py_name: Option<&'static str>,
) {
if self.rec_get_const_obj(name).is_some() {
panic!("already registered: {} {name}", self.name);
} else {
let impl_of = if let ContextKind::MethodDefs(Some(tr)) = &self.kind {
Some(tr.clone())
} else {
None
};
// TODO: not all value objects are comparable
let vi = VarInfo::new(
v_enum(set! {obj.clone()}),
Const,
vis,
Builtin,
None,
impl_of,
py_name.map(Str::ever),
AbsLocation::unknown(),
);
self.consts.insert(VarName::from_str(Str::rc(name)), obj);
self.locals.insert(VarName::from_str(Str::rc(name)), vi);
}
}
fn register_const_param_defaults(&mut self, name: &'static str, params: Vec<ConstTemplate>) {
if self.const_param_defaults.get(name).is_some() {
panic!("already registered: {} {name}", self.name);