feat: add const filter/max/min/not/str/zip

This commit is contained in:
Shunsuke Shibayama 2024-01-29 20:54:30 +09:00
parent d1fa616aea
commit d748333a0f
3 changed files with 242 additions and 8 deletions

View file

@ -867,6 +867,49 @@ pub(crate) fn any_func(mut args: ValueArgs, _ctx: &Context) -> EvalValueResult<T
Ok(ValueObj::Bool(any).into())
}
pub(crate) fn filter_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<TyParam> {
let iterable = args
.remove_left_or_key("iterable")
.ok_or_else(|| not_passed("iterable"))?;
let func = args
.remove_left_or_key("func")
.ok_or_else(|| not_passed("func"))?;
let arr = match iterable {
ValueObj::Array(a) => a.to_vec(),
ValueObj::Tuple(t) => t.to_vec(),
ValueObj::Set(s) => s.into_iter().collect(),
_ => {
return Err(type_mismatch("Iterable(T)", iterable, "iterable"));
}
};
let subr = match func {
ValueObj::Subr(f) => f,
_ => {
return Err(type_mismatch("Subr", func, "func"));
}
};
let mut filtered = vec![];
for v in arr.into_iter() {
let args = ValueArgs::pos_only(vec![v.clone()]);
match ctx.call(subr.clone(), args, Location::Unknown) {
Ok(res) => match ctx.convert_tp_into_value(res) {
Ok(res) => {
if res.is_true() {
filtered.push(v);
}
}
Err(tp) => {
return Err(type_mismatch("Bool", tp, "func"));
}
},
Err(mut err) => {
return Err(EvalValueError::from(*err.remove(0).core));
}
}
}
Ok(TyParam::Value(ValueObj::Array(filtered.into())))
}
pub(crate) fn len_func(mut args: ValueArgs, _ctx: &Context) -> EvalValueResult<TyParam> {
let container = args
.remove_left_or_key("iterable")
@ -921,6 +964,93 @@ pub(crate) fn map_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<Ty
Ok(TyParam::Array(mapped))
}
pub(crate) fn max_func(mut args: ValueArgs, _ctx: &Context) -> EvalValueResult<TyParam> {
let iterable = args
.remove_left_or_key("iterable")
.ok_or_else(|| not_passed("iterable"))?;
let arr = match iterable {
ValueObj::Array(a) => a.to_vec(),
ValueObj::Tuple(t) => t.to_vec(),
ValueObj::Set(s) => s.into_iter().collect(),
_ => {
return Err(type_mismatch("Iterable(Ord)", iterable, "iterable"));
}
};
let mut max = ValueObj::NegInf;
if arr.is_empty() {
return Err(ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
"max() arg is an empty sequence",
line!() as usize,
ErrorKind::ValueError,
Location::Unknown,
)
.into());
}
for v in arr.into_iter() {
if v.is_num() {
if max.clone().try_lt(v.clone()).is_some_and(|b| b.is_true()) {
max = v;
}
} else {
return Err(type_mismatch("Ord", v, "iterable.next()"));
}
}
Ok(max.into())
}
pub(crate) fn min_func(mut args: ValueArgs, _ctx: &Context) -> EvalValueResult<TyParam> {
let iterable = args
.remove_left_or_key("iterable")
.ok_or_else(|| not_passed("iterable"))?;
let arr = match iterable {
ValueObj::Array(a) => a.to_vec(),
ValueObj::Tuple(t) => t.to_vec(),
ValueObj::Set(s) => s.into_iter().collect(),
_ => {
return Err(type_mismatch("Iterable(Ord)", iterable, "iterable"));
}
};
let mut min = ValueObj::Inf;
if arr.is_empty() {
return Err(ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
"min() arg is an empty sequence",
line!() as usize,
ErrorKind::ValueError,
Location::Unknown,
)
.into());
}
for v in arr.into_iter() {
if v.is_num() {
if min.clone().try_gt(v.clone()).is_some_and(|b| b.is_true()) {
min = v;
}
} else {
return Err(type_mismatch("Ord", v, "iterable.next()"));
}
}
Ok(min.into())
}
pub(crate) fn not_func(mut args: ValueArgs, _ctx: &Context) -> EvalValueResult<TyParam> {
let val = args
.remove_left_or_key("val")
.ok_or_else(|| not_passed("val"))?;
match val {
ValueObj::Bool(b) => Ok(ValueObj::Bool(!b).into()),
_ => Err(type_mismatch("Bool", val, "val")),
}
}
pub(crate) fn str_func(mut args: ValueArgs, _ctx: &Context) -> EvalValueResult<TyParam> {
let val = args
.remove_left_or_key("val")
.ok_or_else(|| not_passed("val"))?;
Ok(ValueObj::Str(val.to_string().into()).into())
}
pub(crate) fn resolve_path_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<TyParam> {
let path = args
.remove_left_or_key("Path")
@ -1003,3 +1133,34 @@ pub(crate) fn pred_func(mut args: ValueArgs, _ctx: &Context) -> EvalValueResult<
};
Ok(val.into())
}
// TODO: varargs
pub(crate) fn zip_func(mut args: ValueArgs, _ctx: &Context) -> EvalValueResult<TyParam> {
let iterable1 = args
.remove_left_or_key("iterable1")
.ok_or_else(|| not_passed("iterable1"))?;
let iterable2 = args
.remove_left_or_key("iterable2")
.ok_or_else(|| not_passed("iterable2"))?;
let iterable1 = match iterable1 {
ValueObj::Array(a) => a.to_vec(),
ValueObj::Tuple(t) => t.to_vec(),
ValueObj::Set(s) => s.into_iter().collect(),
_ => {
return Err(type_mismatch("Iterable(T)", iterable1, "iterable1"));
}
};
let iterable2 = match iterable2 {
ValueObj::Array(a) => a.to_vec(),
ValueObj::Tuple(t) => t.to_vec(),
ValueObj::Set(s) => s.into_iter().collect(),
_ => {
return Err(type_mismatch("Iterable(T)", iterable2, "iterable2"));
}
};
let mut zipped = vec![];
for (v1, v2) in iterable1.into_iter().zip(iterable2.into_iter()) {
zipped.push(ValueObj::Tuple(vec![v1, v2].into()));
}
Ok(TyParam::Value(ValueObj::Array(zipped.into())))
}

View file

@ -122,6 +122,12 @@ impl Context {
poly(FILTER, vec![ty_tp(T.clone())]),
)
.quantify();
let filter = ValueObj::Subr(ConstSubr::Builtin(BuiltinConstSubr::new(
FUNC_FILTER,
filter_func,
t_filter.clone(),
None,
)));
let t_format = no_var_func(vec![kw(KW_VALUE, Obj)], vec![kw(KW_SPEC, Str)], Str);
let t_frozenset = nd_func(
vec![kw(KW_ITERABLE, poly(ITERABLE, vec![ty_tp(T.clone())]))],
@ -228,6 +234,12 @@ impl Context {
O.clone(),
)
.quantify();
let max = ValueObj::Subr(ConstSubr::Builtin(BuiltinConstSubr::new(
FUNC_MAX,
max_func,
t_max.clone(),
None,
)));
let t_memoryview = nd_func(
vec![kw(
KW_OBJ,
@ -242,10 +254,22 @@ impl Context {
O,
)
.quantify();
let min = ValueObj::Subr(ConstSubr::Builtin(BuiltinConstSubr::new(
FUNC_MIN,
min_func,
t_min.clone(),
None,
)));
let t_nat = nd_func(vec![kw(KW_OBJ, Obj)], None, Nat);
// e.g. not(b: Bool!): Bool!
let B = mono_q(TY_B, subtypeof(Bool));
let t_not = nd_func(vec![kw(KW_B, B.clone())], None, B).quantify();
let not = ValueObj::Subr(ConstSubr::Builtin(BuiltinConstSubr::new(
FUNC_NOT,
not_func,
t_not.clone(),
None,
)));
let t_oct = nd_func(vec![kw(KW_X, Int)], None, Str);
let t_ord = nd_func(vec![kw(KW_C, Str)], None, Nat);
let t_panic = nd_func(vec![kw(KW_MSG, Str)], None, Never);
@ -298,6 +322,12 @@ impl Context {
.quantify();
let t_staticmethod = nd_func(vec![kw(KW_FUNC, F.clone())], None, F.clone()).quantify();
let t_str = nd_func(vec![kw(KW_OBJECT, Obj)], None, Str);
let str_ = ValueObj::Subr(ConstSubr::Builtin(BuiltinConstSubr::new(
FUNC_STR,
str_func,
t_str.clone(),
None,
)));
let A = mono_q(TY_A, Constraint::Uninited);
let A = mono_q(TY_A, subtypeof(poly(ADD, vec![ty_tp(A)])));
let t_sum = no_var_func(
@ -316,6 +346,12 @@ impl Context {
poly(ZIP, vec![ty_tp(T.clone()), ty_tp(U.clone())]),
)
.quantify();
let zip = ValueObj::Subr(ConstSubr::Builtin(BuiltinConstSubr::new(
FUNC_ZIP,
zip_func,
t_zip.clone(),
None,
)));
self.register_py_builtin_const(
FUNC_ABS,
vis.clone(),
@ -399,12 +435,13 @@ impl Context {
vis.clone(),
Some(FUNC_FORMAT),
);
self.register_builtin_py_impl(
self.register_py_builtin_const(
FUNC_FILTER,
t_filter,
Immutable,
vis.clone(),
Some(t_filter),
filter,
Some(FUNC_FILTER),
None,
);
self.register_builtin_py_impl(FUNC_FROZENSET, t_frozenset, Immutable, vis.clone(), None);
self.register_builtin_py_impl(
@ -453,7 +490,14 @@ impl Context {
Some(FUNC_MAP),
None,
);
self.register_builtin_py_impl(FUNC_MAX, t_max, Immutable, vis.clone(), Some(FUNC_MAX));
self.register_py_builtin_const(
FUNC_MAX,
vis.clone(),
Some(t_max),
max,
Some(FUNC_MAX),
None,
);
self.register_builtin_py_impl(
FUNC_MEMORYVIEW,
t_memoryview,
@ -461,8 +505,15 @@ impl Context {
vis.clone(),
Some(FUNC_MEMORYVIEW),
);
self.register_builtin_py_impl(FUNC_MIN, t_min, Immutable, vis.clone(), Some(FUNC_MIN));
self.register_builtin_py_impl(FUNC_NOT, t_not, Immutable, vis.clone(), None); // `not` is not a function in Python
self.register_py_builtin_const(
FUNC_MIN,
vis.clone(),
Some(t_min),
min,
Some(FUNC_MIN),
None,
);
self.register_py_builtin_const(FUNC_NOT, vis.clone(), Some(t_not), not, None, None); // `not` is not a function in Python
self.register_builtin_py_impl(FUNC_OCT, t_oct, Immutable, vis.clone(), Some(FUNC_OCT));
self.register_builtin_py_impl(FUNC_ORD, t_ord, Immutable, vis.clone(), Some(FUNC_ORD));
self.register_builtin_py_impl(FUNC_POW, t_pow, Immutable, vis.clone(), Some(FUNC_POW));
@ -559,9 +610,23 @@ impl Context {
vis.clone(),
Some(FUNC_STATICMETHOD),
);
self.register_builtin_py_impl(FUNC_STR, t_str, Immutable, vis.clone(), Some(FUNC_STR__));
self.register_py_builtin_const(
FUNC_STR,
vis.clone(),
Some(t_str),
str_,
Some(FUNC_STR__),
None,
);
self.register_builtin_py_impl(FUNC_SUM, t_sum, Immutable, vis.clone(), Some(FUNC_SUM));
self.register_builtin_py_impl(FUNC_ZIP, t_zip, Immutable, vis.clone(), Some(FUNC_ZIP));
self.register_py_builtin_const(
FUNC_ZIP,
vis.clone(),
Some(t_zip),
zip,
Some(FUNC_ZIP),
None,
);
let name = if PYTHON_MODE { FUNC_INT } else { FUNC_INT__ };
self.register_builtin_py_impl(FUNC_INT, t_int, Immutable, vis.clone(), Some(name));
if DEBUG_MODE {