mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-28 12:14:43 +00:00
feat: bidi for containers
This commit is contained in:
parent
0f430199ab
commit
712d4e2b73
3 changed files with 138 additions and 20 deletions
|
@ -1267,3 +1267,26 @@ pub trait StructuralEq {
|
|||
pub trait __Str__ {
|
||||
fn __str__(&self) -> String;
|
||||
}
|
||||
|
||||
pub trait OptionalTranspose {
|
||||
type Output;
|
||||
type Fill;
|
||||
/// `self: Option<_>`
|
||||
fn transpose(self, fill: Self::Fill) -> Self::Output
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
|
||||
impl<T: Clone> OptionalTranspose for Option<Vec<T>> {
|
||||
type Output = Vec<Option<T>>;
|
||||
type Fill = usize;
|
||||
fn transpose(self, fill: Self::Fill) -> Self::Output
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
match self {
|
||||
Some(v) => v.into_iter().map(Some).collect(),
|
||||
None => vec![None; fill],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1790,6 +1790,38 @@ impl Context {
|
|||
self.convert_tp_into_value(fv.crack().clone())
|
||||
}
|
||||
TyParam::Value(v) => Ok(v),
|
||||
TyParam::Array(arr) => {
|
||||
let mut new = vec![];
|
||||
for elem in arr {
|
||||
let elem = self.convert_tp_into_value(elem)?;
|
||||
new.push(elem);
|
||||
}
|
||||
Ok(ValueObj::Array(new.into()))
|
||||
}
|
||||
TyParam::Tuple(tys) => {
|
||||
let mut new = vec![];
|
||||
for elem in tys {
|
||||
let elem = self.convert_tp_into_value(elem)?;
|
||||
new.push(elem);
|
||||
}
|
||||
Ok(ValueObj::Tuple(new.into()))
|
||||
}
|
||||
TyParam::Record(rec) => {
|
||||
let mut new = dict! {};
|
||||
for (name, elem) in rec {
|
||||
let elem = self.convert_tp_into_value(elem)?;
|
||||
new.insert(name, elem);
|
||||
}
|
||||
Ok(ValueObj::Record(new))
|
||||
}
|
||||
TyParam::Set(set) => {
|
||||
let mut new = set! {};
|
||||
for elem in set {
|
||||
let elem = self.convert_tp_into_value(elem)?;
|
||||
new.insert(elem);
|
||||
}
|
||||
Ok(ValueObj::Set(new))
|
||||
}
|
||||
other => self.convert_tp_into_type(other).map(ValueObj::builtin_type),
|
||||
}
|
||||
}
|
||||
|
@ -1931,12 +1963,12 @@ impl Context {
|
|||
}
|
||||
}
|
||||
|
||||
fn _convert_type_to_dict_type(&self, ty: Type) -> Result<Dict<Type, Type>, ()> {
|
||||
pub(crate) fn convert_type_to_dict_type(&self, ty: Type) -> Result<Dict<Type, Type>, ()> {
|
||||
match ty {
|
||||
Type::FreeVar(fv) if fv.is_linked() => {
|
||||
self._convert_type_to_dict_type(fv.crack().clone())
|
||||
self.convert_type_to_dict_type(fv.crack().clone())
|
||||
}
|
||||
Type::Refinement(refine) => self._convert_type_to_dict_type(*refine.t),
|
||||
Type::Refinement(refine) => self.convert_type_to_dict_type(*refine.t),
|
||||
Type::Poly { name, params } if &name[..] == "Dict" => {
|
||||
let dict = Dict::try_from(params[0].clone())?;
|
||||
let mut new_dict = dict! {};
|
||||
|
@ -1951,6 +1983,25 @@ impl Context {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn convert_type_to_tuple_type(&self, ty: Type) -> Result<Vec<Type>, ()> {
|
||||
match ty {
|
||||
Type::FreeVar(fv) if fv.is_linked() => {
|
||||
self.convert_type_to_tuple_type(fv.crack().clone())
|
||||
}
|
||||
Type::Refinement(refine) => self.convert_type_to_tuple_type(*refine.t),
|
||||
Type::Poly { name, params } if &name[..] == "Tuple" => {
|
||||
let tps = Vec::try_from(params[0].clone())?;
|
||||
let mut tys = vec![];
|
||||
for elem in tps.into_iter() {
|
||||
let elem = self.convert_tp_into_type(elem).map_err(|_| ())?;
|
||||
tys.push(elem);
|
||||
}
|
||||
Ok(tys)
|
||||
}
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn convert_type_to_array(&self, ty: Type) -> Result<Vec<ValueObj>, Type> {
|
||||
match ty {
|
||||
Type::FreeVar(fv) if fv.is_linked() => self.convert_type_to_array(fv.crack().clone()),
|
||||
|
|
|
@ -11,6 +11,7 @@ use erg_common::error::{Location, MultiErrorDisplay};
|
|||
use erg_common::fresh::FreshNameGenerator;
|
||||
use erg_common::set;
|
||||
use erg_common::set::Set;
|
||||
use erg_common::traits::OptionalTranspose;
|
||||
use erg_common::traits::{ExitStatus, Locational, NoTypeDisplay, Runnable, Stream};
|
||||
use erg_common::triple::Triple;
|
||||
use erg_common::{fmt_option, fn_name, log, switch_lang, Str};
|
||||
|
@ -294,15 +295,21 @@ impl ASTLowerer {
|
|||
fn lower_normal_array(
|
||||
&mut self,
|
||||
array: ast::NormalArray,
|
||||
_expect: Option<&Type>,
|
||||
expect: Option<&Type>,
|
||||
) -> LowerResult<hir::NormalArray> {
|
||||
log!(info "entered {}({array})", fn_name!());
|
||||
let mut new_array = vec![];
|
||||
let eval_result = self.module.context.eval_const_normal_array(&array);
|
||||
let (elems, ..) = array.elems.deconstruct();
|
||||
let expect_elem = expect.and_then(|t| {
|
||||
self.module
|
||||
.context
|
||||
.convert_tp_into_type(t.typarams().get(0)?.clone())
|
||||
.ok()
|
||||
});
|
||||
let mut union = Type::Never;
|
||||
for elem in elems.into_iter() {
|
||||
let elem = self.lower_expr(elem.expr, None)?;
|
||||
let elem = self.lower_expr(elem.expr, expect_elem.as_ref())?;
|
||||
let union_ = self.module.context.union(&union, elem.ref_t());
|
||||
if let Some((l, r)) = union_.union_pair() {
|
||||
match (l.is_unbound_var(), r.is_unbound_var()) {
|
||||
|
@ -352,12 +359,18 @@ impl ASTLowerer {
|
|||
fn lower_array_with_length(
|
||||
&mut self,
|
||||
array: ast::ArrayWithLength,
|
||||
_expect: Option<&Type>,
|
||||
expect: Option<&Type>,
|
||||
) -> LowerResult<hir::ArrayWithLength> {
|
||||
log!(info "entered {}({array})", fn_name!());
|
||||
let elem = self.lower_expr(array.elem.expr, None)?;
|
||||
let expect_elem = expect.and_then(|t| {
|
||||
self.module
|
||||
.context
|
||||
.convert_tp_into_type(t.typarams().get(0)?.clone())
|
||||
.ok()
|
||||
});
|
||||
let elem = self.lower_expr(array.elem.expr, expect_elem.as_ref())?;
|
||||
let array_t = self.gen_array_with_length_type(&elem, &array.len);
|
||||
let len = self.lower_expr(*array.len, None)?;
|
||||
let len = self.lower_expr(*array.len, Some(&Type::Nat))?;
|
||||
let hir_array = hir::ArrayWithLength::new(array.l_sqbr, array.r_sqbr, array_t, elem, len);
|
||||
Ok(hir_array)
|
||||
}
|
||||
|
@ -384,13 +397,20 @@ impl ASTLowerer {
|
|||
fn lower_normal_tuple(
|
||||
&mut self,
|
||||
tuple: ast::NormalTuple,
|
||||
_expect: Option<&Type>,
|
||||
expect: Option<&Type>,
|
||||
) -> LowerResult<hir::NormalTuple> {
|
||||
log!(info "entered {}({tuple})", fn_name!());
|
||||
let expect = expect.and_then(|exp| {
|
||||
self.module
|
||||
.context
|
||||
.convert_type_to_tuple_type(exp.clone())
|
||||
.ok()
|
||||
});
|
||||
let mut new_tuple = vec![];
|
||||
let (elems, .., paren) = tuple.elems.deconstruct();
|
||||
for elem in elems {
|
||||
let elem = self.lower_expr(elem.expr, None)?;
|
||||
let expect_ts = expect.transpose(elems.len());
|
||||
for (elem, expect) in elems.into_iter().zip(expect_ts) {
|
||||
let elem = self.lower_expr(elem.expr, expect.as_ref())?;
|
||||
new_tuple.push(elem);
|
||||
}
|
||||
Ok(hir::NormalTuple::new(hir::Args::values(new_tuple, paren)))
|
||||
|
@ -463,14 +483,20 @@ impl ASTLowerer {
|
|||
fn lower_normal_set(
|
||||
&mut self,
|
||||
set: ast::NormalSet,
|
||||
_expect: Option<&Type>,
|
||||
expect: Option<&Type>,
|
||||
) -> LowerResult<hir::NormalSet> {
|
||||
log!(info "entered {}({set})", fn_name!());
|
||||
let (elems, ..) = set.elems.deconstruct();
|
||||
let expect_elem = expect.and_then(|t| {
|
||||
self.module
|
||||
.context
|
||||
.convert_tp_into_type(t.typarams().get(0)?.clone())
|
||||
.ok()
|
||||
});
|
||||
let mut union = Type::Never;
|
||||
let mut new_set = vec![];
|
||||
for elem in elems {
|
||||
let elem = self.lower_expr(elem.expr, None)?;
|
||||
let elem = self.lower_expr(elem.expr, expect_elem.as_ref())?;
|
||||
union = self.module.context.union(&union, elem.ref_t());
|
||||
if ERG_MODE && union.is_union_type() {
|
||||
return Err(LowerErrors::from(LowerError::syntax_error(
|
||||
|
@ -542,12 +568,18 @@ impl ASTLowerer {
|
|||
fn lower_set_with_length(
|
||||
&mut self,
|
||||
set: ast::SetWithLength,
|
||||
_expect: Option<&Type>,
|
||||
expect: Option<&Type>,
|
||||
) -> LowerResult<hir::SetWithLength> {
|
||||
log!("entered {}({set})", fn_name!());
|
||||
let elem = self.lower_expr(set.elem.expr, None)?;
|
||||
let expect_elem = expect.and_then(|t| {
|
||||
self.module
|
||||
.context
|
||||
.convert_tp_into_type(t.typarams().get(0)?.clone())
|
||||
.ok()
|
||||
});
|
||||
let elem = self.lower_expr(set.elem.expr, expect_elem.as_ref())?;
|
||||
let set_t = self.gen_set_with_length_type(&elem, &set.len);
|
||||
let len = self.lower_expr(*set.len, None)?;
|
||||
let len = self.lower_expr(*set.len, Some(&Type::Nat))?;
|
||||
let hir_set = hir::SetWithLength::new(set.l_brace, set.r_brace, set_t, elem, len);
|
||||
Ok(hir_set)
|
||||
}
|
||||
|
@ -585,14 +617,23 @@ impl ASTLowerer {
|
|||
fn lower_normal_dict(
|
||||
&mut self,
|
||||
dict: ast::NormalDict,
|
||||
_expect: Option<&Type>,
|
||||
expect: Option<&Type>,
|
||||
) -> LowerResult<hir::NormalDict> {
|
||||
log!(info "enter {}({dict})", fn_name!());
|
||||
let mut union = dict! {};
|
||||
let mut new_kvs = vec![];
|
||||
for kv in dict.kvs {
|
||||
let key = self.lower_expr(kv.key, None)?;
|
||||
let value = self.lower_expr(kv.value, None)?;
|
||||
let expect = expect
|
||||
.and_then(|exp| {
|
||||
self.module
|
||||
.context
|
||||
.convert_type_to_dict_type(exp.clone())
|
||||
.ok()
|
||||
})
|
||||
.map(|dict| dict.into_iter().collect::<Vec<_>>());
|
||||
let expect_kvs = expect.transpose(dict.kvs.len());
|
||||
for (kv, expect) in dict.kvs.into_iter().zip(expect_kvs) {
|
||||
let key = self.lower_expr(kv.key, expect.as_ref().map(|(k, _)| k))?;
|
||||
let value = self.lower_expr(kv.value, expect.as_ref().map(|(_, v)| v))?;
|
||||
if let Some(popped_val_t) = union.insert(key.t(), value.t()) {
|
||||
if PYTHON_MODE {
|
||||
let val_t = union.get_mut(key.ref_t()).unwrap();
|
||||
|
@ -2434,6 +2475,9 @@ impl ASTLowerer {
|
|||
.module
|
||||
.context
|
||||
.instantiate_typespec(&tasc.t_spec.t_spec)?;
|
||||
let expect = expect.map_or(Some(&spec_t), |exp| {
|
||||
self.module.context.min(exp, &spec_t).ok().or(Some(&spec_t))
|
||||
});
|
||||
let expr = self.lower_expr(*tasc.expr, expect)?;
|
||||
match kind {
|
||||
AscriptionKind::TypeOf | AscriptionKind::AsCast => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue