mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-28 20:14:45 +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__ {
|
pub trait __Str__ {
|
||||||
fn __str__(&self) -> String;
|
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())
|
self.convert_tp_into_value(fv.crack().clone())
|
||||||
}
|
}
|
||||||
TyParam::Value(v) => Ok(v),
|
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),
|
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 {
|
match ty {
|
||||||
Type::FreeVar(fv) if fv.is_linked() => {
|
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" => {
|
Type::Poly { name, params } if &name[..] == "Dict" => {
|
||||||
let dict = Dict::try_from(params[0].clone())?;
|
let dict = Dict::try_from(params[0].clone())?;
|
||||||
let mut new_dict = dict! {};
|
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> {
|
pub(crate) fn convert_type_to_array(&self, ty: Type) -> Result<Vec<ValueObj>, Type> {
|
||||||
match ty {
|
match ty {
|
||||||
Type::FreeVar(fv) if fv.is_linked() => self.convert_type_to_array(fv.crack().clone()),
|
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::fresh::FreshNameGenerator;
|
||||||
use erg_common::set;
|
use erg_common::set;
|
||||||
use erg_common::set::Set;
|
use erg_common::set::Set;
|
||||||
|
use erg_common::traits::OptionalTranspose;
|
||||||
use erg_common::traits::{ExitStatus, Locational, NoTypeDisplay, Runnable, Stream};
|
use erg_common::traits::{ExitStatus, Locational, NoTypeDisplay, Runnable, Stream};
|
||||||
use erg_common::triple::Triple;
|
use erg_common::triple::Triple;
|
||||||
use erg_common::{fmt_option, fn_name, log, switch_lang, Str};
|
use erg_common::{fmt_option, fn_name, log, switch_lang, Str};
|
||||||
|
@ -294,15 +295,21 @@ impl ASTLowerer {
|
||||||
fn lower_normal_array(
|
fn lower_normal_array(
|
||||||
&mut self,
|
&mut self,
|
||||||
array: ast::NormalArray,
|
array: ast::NormalArray,
|
||||||
_expect: Option<&Type>,
|
expect: Option<&Type>,
|
||||||
) -> LowerResult<hir::NormalArray> {
|
) -> LowerResult<hir::NormalArray> {
|
||||||
log!(info "entered {}({array})", fn_name!());
|
log!(info "entered {}({array})", fn_name!());
|
||||||
let mut new_array = vec![];
|
let mut new_array = vec![];
|
||||||
let eval_result = self.module.context.eval_const_normal_array(&array);
|
let eval_result = self.module.context.eval_const_normal_array(&array);
|
||||||
let (elems, ..) = array.elems.deconstruct();
|
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;
|
let mut union = Type::Never;
|
||||||
for elem in elems.into_iter() {
|
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());
|
let union_ = self.module.context.union(&union, elem.ref_t());
|
||||||
if let Some((l, r)) = union_.union_pair() {
|
if let Some((l, r)) = union_.union_pair() {
|
||||||
match (l.is_unbound_var(), r.is_unbound_var()) {
|
match (l.is_unbound_var(), r.is_unbound_var()) {
|
||||||
|
@ -352,12 +359,18 @@ impl ASTLowerer {
|
||||||
fn lower_array_with_length(
|
fn lower_array_with_length(
|
||||||
&mut self,
|
&mut self,
|
||||||
array: ast::ArrayWithLength,
|
array: ast::ArrayWithLength,
|
||||||
_expect: Option<&Type>,
|
expect: Option<&Type>,
|
||||||
) -> LowerResult<hir::ArrayWithLength> {
|
) -> LowerResult<hir::ArrayWithLength> {
|
||||||
log!(info "entered {}({array})", fn_name!());
|
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 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);
|
let hir_array = hir::ArrayWithLength::new(array.l_sqbr, array.r_sqbr, array_t, elem, len);
|
||||||
Ok(hir_array)
|
Ok(hir_array)
|
||||||
}
|
}
|
||||||
|
@ -384,13 +397,20 @@ impl ASTLowerer {
|
||||||
fn lower_normal_tuple(
|
fn lower_normal_tuple(
|
||||||
&mut self,
|
&mut self,
|
||||||
tuple: ast::NormalTuple,
|
tuple: ast::NormalTuple,
|
||||||
_expect: Option<&Type>,
|
expect: Option<&Type>,
|
||||||
) -> LowerResult<hir::NormalTuple> {
|
) -> LowerResult<hir::NormalTuple> {
|
||||||
log!(info "entered {}({tuple})", fn_name!());
|
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 mut new_tuple = vec![];
|
||||||
let (elems, .., paren) = tuple.elems.deconstruct();
|
let (elems, .., paren) = tuple.elems.deconstruct();
|
||||||
for elem in elems {
|
let expect_ts = expect.transpose(elems.len());
|
||||||
let elem = self.lower_expr(elem.expr, None)?;
|
for (elem, expect) in elems.into_iter().zip(expect_ts) {
|
||||||
|
let elem = self.lower_expr(elem.expr, expect.as_ref())?;
|
||||||
new_tuple.push(elem);
|
new_tuple.push(elem);
|
||||||
}
|
}
|
||||||
Ok(hir::NormalTuple::new(hir::Args::values(new_tuple, paren)))
|
Ok(hir::NormalTuple::new(hir::Args::values(new_tuple, paren)))
|
||||||
|
@ -463,14 +483,20 @@ impl ASTLowerer {
|
||||||
fn lower_normal_set(
|
fn lower_normal_set(
|
||||||
&mut self,
|
&mut self,
|
||||||
set: ast::NormalSet,
|
set: ast::NormalSet,
|
||||||
_expect: Option<&Type>,
|
expect: Option<&Type>,
|
||||||
) -> LowerResult<hir::NormalSet> {
|
) -> LowerResult<hir::NormalSet> {
|
||||||
log!(info "entered {}({set})", fn_name!());
|
log!(info "entered {}({set})", fn_name!());
|
||||||
let (elems, ..) = set.elems.deconstruct();
|
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 union = Type::Never;
|
||||||
let mut new_set = vec![];
|
let mut new_set = vec![];
|
||||||
for elem in elems {
|
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());
|
union = self.module.context.union(&union, elem.ref_t());
|
||||||
if ERG_MODE && union.is_union_type() {
|
if ERG_MODE && union.is_union_type() {
|
||||||
return Err(LowerErrors::from(LowerError::syntax_error(
|
return Err(LowerErrors::from(LowerError::syntax_error(
|
||||||
|
@ -542,12 +568,18 @@ impl ASTLowerer {
|
||||||
fn lower_set_with_length(
|
fn lower_set_with_length(
|
||||||
&mut self,
|
&mut self,
|
||||||
set: ast::SetWithLength,
|
set: ast::SetWithLength,
|
||||||
_expect: Option<&Type>,
|
expect: Option<&Type>,
|
||||||
) -> LowerResult<hir::SetWithLength> {
|
) -> LowerResult<hir::SetWithLength> {
|
||||||
log!("entered {}({set})", fn_name!());
|
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 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);
|
let hir_set = hir::SetWithLength::new(set.l_brace, set.r_brace, set_t, elem, len);
|
||||||
Ok(hir_set)
|
Ok(hir_set)
|
||||||
}
|
}
|
||||||
|
@ -585,14 +617,23 @@ impl ASTLowerer {
|
||||||
fn lower_normal_dict(
|
fn lower_normal_dict(
|
||||||
&mut self,
|
&mut self,
|
||||||
dict: ast::NormalDict,
|
dict: ast::NormalDict,
|
||||||
_expect: Option<&Type>,
|
expect: Option<&Type>,
|
||||||
) -> LowerResult<hir::NormalDict> {
|
) -> LowerResult<hir::NormalDict> {
|
||||||
log!(info "enter {}({dict})", fn_name!());
|
log!(info "enter {}({dict})", fn_name!());
|
||||||
let mut union = dict! {};
|
let mut union = dict! {};
|
||||||
let mut new_kvs = vec![];
|
let mut new_kvs = vec![];
|
||||||
for kv in dict.kvs {
|
let expect = expect
|
||||||
let key = self.lower_expr(kv.key, None)?;
|
.and_then(|exp| {
|
||||||
let value = self.lower_expr(kv.value, None)?;
|
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 let Some(popped_val_t) = union.insert(key.t(), value.t()) {
|
||||||
if PYTHON_MODE {
|
if PYTHON_MODE {
|
||||||
let val_t = union.get_mut(key.ref_t()).unwrap();
|
let val_t = union.get_mut(key.ref_t()).unwrap();
|
||||||
|
@ -2434,6 +2475,9 @@ impl ASTLowerer {
|
||||||
.module
|
.module
|
||||||
.context
|
.context
|
||||||
.instantiate_typespec(&tasc.t_spec.t_spec)?;
|
.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)?;
|
let expr = self.lower_expr(*tasc.expr, expect)?;
|
||||||
match kind {
|
match kind {
|
||||||
AscriptionKind::TypeOf | AscriptionKind::AsCast => {
|
AscriptionKind::TypeOf | AscriptionKind::AsCast => {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue