Skip to content

Commit

Permalink
Merge branch 'erg-lang:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
GreasySlug authored Sep 21, 2024
2 parents a4b0909 + 9f43570 commit 559dc63
Show file tree
Hide file tree
Showing 13 changed files with 370 additions and 21 deletions.
1 change: 1 addition & 0 deletions crates/erg_common/dict.rs
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ impl<K: Hash + Eq, V> Dict<K, V> {
self.dict.extend(iter);
}

/// If the key already exists, the value will not be updated.
#[inline]
pub fn guaranteed_extend<I: IntoIterator<Item = (K, V)>>(&mut self, other: I) {
for (k, v) in other {
Expand Down
27 changes: 15 additions & 12 deletions crates/erg_compiler/context/initialize/const_func.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,21 +239,21 @@ pub(crate) fn sub_vdict_get<'d>(
) -> Option<&'d ValueObj> {
let mut matches = vec![];
for (k, v) in dict.iter() {
match (key, k) {
(ValueObj::Type(idx), ValueObj::Type(kt))
if ctx.subtype_of(&idx.typ().lower_bounded(), &kt.typ().lower_bounded()) =>
if key == k {
return Some(v);
}
match (ctx.convert_value_into_type(key.clone()), ctx.convert_value_into_type(k.clone())) {
(Ok(idx), Ok(kt))
if ctx.subtype_of(&idx.lower_bounded(), &kt.lower_bounded()) /*|| dict.len() == 1*/ =>
{
matches.push((idx, kt, v));
}
(idx, k) if idx == k => {
return Some(v);
}
_ => {}
}
}
for (idx, kt, v) in matches.into_iter() {
let list = UndoableLinkedList::new();
match ctx.undoable_sub_unify(idx.typ(), kt.typ(), &(), &list, None) {
match ctx.undoable_sub_unify(&idx, &kt, &(), &list, None) {
Ok(_) => {
return Some(v);
}
Expand All @@ -272,21 +272,24 @@ pub(crate) fn sub_tpdict_get<'d>(
) -> Option<&'d TyParam> {
let mut matches = vec![];
for (k, v) in dict.iter() {
match (<&Type>::try_from(key), <&Type>::try_from(k)) {
if key == k {
return Some(v);
}
match (
ctx.convert_tp_into_type(key.clone()),
ctx.convert_tp_into_type(k.clone()),
) {
(Ok(idx), Ok(kt))
if ctx.subtype_of(&idx.lower_bounded(), &kt.lower_bounded()) || dict.len() == 1 =>
{
matches.push((idx, kt, v));
}
(_, _) if key == k => {
return Some(v);
}
_ => {}
}
}
for (idx, kt, v) in matches.into_iter() {
let list = UndoableLinkedList::new();
match ctx.undoable_sub_unify(idx, kt, &(), &list, None) {
match ctx.undoable_sub_unify(&idx, &kt, &(), &list, None) {
Ok(_) => {
return Some(v);
}
Expand Down
13 changes: 11 additions & 2 deletions crates/erg_compiler/context/initialize/funcs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1077,8 +1077,9 @@ impl Context {
);
let E = mono_q(TY_E, subtypeof(mono(EQ)));
let E2 = mono_q(TY_E, subtypeof(mono(IRREGULAR_EQ)));
let op_t = bin_op(E.clone(), E, Bool).quantify()
& bin_op(E2.clone(), E2.clone(), E2.proj(OUTPUT)).quantify();
let op_t = (bin_op(E.clone(), E, Bool).quantify()
& bin_op(E2.clone(), E2.clone(), E2.proj(OUTPUT)).quantify())
.with_default_intersec_index(0);
self.register_builtin_py_impl(
OP_EQ,
op_t.clone(),
Expand Down Expand Up @@ -1380,6 +1381,14 @@ impl Context {
.structuralize();
bin_op(S, R.clone(), Bool).quantify()
};
let op_t2 = {
let S = Type::from(
dict! { Field::public(FUNDAMENTAL_ITER.into()) => fn0_met(Never, poly(ITERATOR, vec![ty_tp(R.clone())])) },
)
.structuralize();
bin_op(S, R.clone(), Bool).quantify()
};
let op_t = (op_t & op_t2).with_default_intersec_index(0);
self.register_builtin_erg_impl(
FUNDAMENTAL_CONTAINS,
op_t.clone(),
Expand Down
8 changes: 7 additions & 1 deletion crates/erg_compiler/context/initialize/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,8 +385,14 @@ impl Context {
let mut iterator = Self::builtin_poly_trait(ITERATOR, vec![PS::t_nd(TY_T)], 2);
iterator.register_superclass(poly(ITERABLE, vec![ty_tp(T.clone())]), &iterable);
let Slf = mono_q(SELF, subtypeof(poly(ITERATOR, vec![ty_tp(T.clone())])));
let t = fn0_met(Slf, or(T.clone(), NoneType)).quantify();
let t = fn0_met(Slf.clone(), or(T.clone(), NoneType)).quantify();
iterator.register_builtin_erg_decl(FUNDAMENTAL_NEXT, t, Visibility::BUILTIN_PUBLIC);
iterator.register_builtin_erg_impl(
FUNDAMENTAL_ITER,
fn0_met(Slf.clone(), Slf.clone()).quantify(),
Const,
Visibility::BUILTIN_PUBLIC,
);
/* Container */
let mut container = Self::builtin_poly_trait(CONTAINER, vec![PS::t_nd(TY_T)], 2);
let op_t = fn1_met(mono(CONTAINER), T.clone(), Bool).quantify();
Expand Down
26 changes: 26 additions & 0 deletions crates/erg_compiler/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1435,6 +1435,32 @@ impl Context {
attrs.guaranteed_extend(sup_ctx.type_dir(namespace));
}
}
for sup in self.super_traits.iter() {
if let Some(sup_ctx) = namespace.get_nominal_type_ctx(sup) {
if sup_ctx.name == self.name {
continue;
}
attrs.guaranteed_extend(sup_ctx.type_impl_dir(namespace));
}
}
attrs
}

fn type_impl_dir<'t>(&'t self, namespace: &'t Context) -> Dict<&VarName, &VarInfo> {
let mut attrs = self.locals.iter().collect::<Dict<_, _>>();
attrs.guaranteed_extend(
self.methods_list
.iter()
.flat_map(|ctx| ctx.type_impl_dir(namespace)),
);
for sup in self.super_classes.iter().chain(self.super_traits.iter()) {
if let Some(sup_ctx) = namespace.get_nominal_type_ctx(sup) {
if sup_ctx.name == self.name {
continue;
}
attrs.guaranteed_extend(sup_ctx.type_impl_dir(namespace));
}
}
attrs
}

Expand Down
88 changes: 87 additions & 1 deletion crates/erg_compiler/context/register.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ use RegistrationMode::*;
use super::eval::Substituter;
use super::instantiate::TyVarCache;
use super::instantiate_spec::ParamKind;
use super::{MethodContext, ParamSpec, TraitImpl, TypeContext};
use super::{ControlKind, MethodContext, ParamSpec, TraitImpl, TypeContext};

pub fn valid_mod_name(name: &str) -> bool {
!name.is_empty() && !name.starts_with('/') && name.trim() == name
Expand Down Expand Up @@ -1103,6 +1103,11 @@ impl Context {
total_errs.extend(errs);
}
}
ast::Expr::Call(call) if PYTHON_MODE => {
if let Err(errs) = self.preregister_control_consts(call) {
total_errs.extend(errs);
}
}
_ => {}
}
}
Expand All @@ -1113,6 +1118,44 @@ impl Context {
}
}

fn preregister_control_consts(&mut self, call: &ast::Call) -> TyCheckResult<()> {
match call
.obj
.get_name()
.and_then(|s| ControlKind::try_from(&s[..]).ok())
{
Some(ControlKind::If) => {
let Some(ast::Expr::Lambda(then)) = call.args.nth_or_key(1, "then") else {
return Ok(());
};
self.preregister_consts(&then.body)?;
if let Some(ast::Expr::Lambda(else_)) = call.args.nth_or_key(2, "else") {
self.preregister_consts(&else_.body)?;
}
}
Some(ControlKind::For) => {
let Some(ast::Expr::Lambda(body)) = call.args.nth_or_key(1, "body") else {
return Ok(());
};
self.preregister_consts(&body.body)?;
}
Some(ControlKind::While) => {
let Some(ast::Expr::Lambda(body)) = call.args.nth_or_key(1, "body") else {
return Ok(());
};
self.preregister_consts(&body.body)?;
}
Some(ControlKind::With) => {
let Some(ast::Expr::Lambda(body)) = call.args.nth_or_key(1, "body") else {
return Ok(());
};
self.preregister_consts(&body.body)?;
}
_ => {}
}
Ok(())
}

pub(crate) fn register_defs(&mut self, block: &ast::Block) -> TyCheckResult<()> {
let mut total_errs = TyCheckErrors::empty();
for expr in block.iter() {
Expand Down Expand Up @@ -1181,6 +1224,11 @@ impl Context {
total_errs.extend(errs);
}
}
ast::Expr::Call(call) if PYTHON_MODE => {
if let Err(errs) = self.register_control_defs(call) {
total_errs.extend(errs);
}
}
_ => {}
}
}
Expand All @@ -1191,6 +1239,44 @@ impl Context {
}
}

fn register_control_defs(&mut self, call: &ast::Call) -> TyCheckResult<()> {
match call
.obj
.get_name()
.and_then(|s| ControlKind::try_from(&s[..]).ok())
{
Some(ControlKind::If) => {
let Some(ast::Expr::Lambda(then)) = call.args.nth_or_key(1, "then") else {
return Ok(());
};
self.register_defs(&then.body)?;
if let Some(ast::Expr::Lambda(else_)) = call.args.nth_or_key(2, "else") {
self.register_defs(&else_.body)?;
}
}
Some(ControlKind::For) => {
let Some(ast::Expr::Lambda(body)) = call.args.nth_or_key(1, "body") else {
return Ok(());
};
self.register_defs(&body.body)?;
}
Some(ControlKind::While) => {
let Some(ast::Expr::Lambda(body)) = call.args.nth_or_key(1, "body") else {
return Ok(());
};
self.register_defs(&body.body)?;
}
Some(ControlKind::With) => {
let Some(ast::Expr::Lambda(body)) = call.args.nth_or_key(1, "body") else {
return Ok(());
};
self.register_defs(&body.body)?;
}
_ => {}
}
Ok(())
}

/// HACK: The constant expression evaluator can evaluate attributes when the type of the receiver is known.
/// import/pyimport is not a constant function, but specially assumes that the type of the module is known in the eval phase.
fn pre_import(&mut self, def: &ast::Def) -> TyCheckResult<()> {
Expand Down
84 changes: 84 additions & 0 deletions crates/erg_compiler/lib/pystd/codecs.d.er
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
.BOM: Bytes
.BOM_BE: Bytes
.BOM_LE: Bytes
.BOM_UTF8: Bytes
.BOM_UTF16: Bytes
.BOM_UTF16_BE: Bytes
.BOM_UTF16_LE: Bytes
.BOM_UTF32: Bytes
.BOM_UTF32_BE: Bytes
.BOM_UTF32_LE: Bytes

.EncodedFile: ClassType

.StreamReader!: ClassType
.StreamReader!.
read!: (self: RefMut StreamReader!, size := Int, chars := Int, firstline := Bool) => Bytes
readline!: (self: RefMut StreamReader!, size := Int, keepends := Bool) => Bytes
readlines!: (self: RefMut StreamReader!, sizehint := Int, keepends := Bool) => List Bytes
reset!: (self: RefMut StreamReader!) => NoneType
__iter__: (self: Ref StreamReader!) => Iterator Bytes

.StreamWriter!: ClassType
.StreamWriter!.
write!: (self: RefMut StreamWriter!, obj: Bytes) => Int
writelines!: (self: RefMut StreamWriter!, obj: List Bytes) => NoneType
reset!: (self: RefMut StreamWriter!) => NoneType

.StreamReaderWriter!: ClassType
.StreamReaderWriter!.
read!: (self: RefMut StreamReaderWriter!, size := Int, chars := Int, firstline := Bool) => Bytes
readline!: (self: RefMut StreamReaderWriter!, size := Int, keepends := Bool) => Bytes
readlines!: (self: RefMut StreamReaderWriter!, sizehint := Int, keepends := Bool) => List Bytes
write!: (self: RefMut StreamReaderWriter!, obj: Bytes) => Int
writelines!: (self: RefMut StreamReaderWriter!, obj: List Bytes) => NoneType
reset!: (self: RefMut StreamReaderWriter!) => NoneType
__iter__: (self: Ref StreamReaderWriter!) => Iterator Bytes

.Codec: ClassType
.Codec.
name: Str
encode: (obj: Str, errors := Str) -> Bytes
decode: (obj: Bytes, errors := Str) -> Str

.CodecInfo: ClassType
.CodecInfo.
name: Str
encode: (obj: Str, encoding := Str, errors := Str) -> Bytes
decode: (obj: Bytes, encoding := Str, errors:= Str) -> Str
streamreader: (obj: Bytes, errors: Str) -> StreamReader!
streamwriter: (obj: Bytes, errors: Str) -> StreamWriter!
__call__: (
encode: (obj: Str, encoding := Str, errors := Str) -> Bytes,
decode: (obj: Bytes, encoding := Str, errors := Str) -> Str,
streamreader := StreamReader!,
streamwriter := StreamWriter!,
incrementalencoder := IncrementalEncoder,
incrementaldecoder := IncrementalDecoder,
name := Str,
) -> CodecInfo

.IncrementalEncoder: ClassType
.IncrementalEncoder.
encode: (obj: Str, final := Bool) -> Bytes

.IncrementalDecoder: ClassType
.IncrementalDecoder.
decode: (obj: Bytes, final := Bool) -> Str

.BufferedIncrementalEncoder: ClassType
.BufferedIncrementalEncoder <: IncrementalEncoder

.BufferedIncrementalDecoder: ClassType
.BufferedIncrementalDecoder <: IncrementalDecoder

.encode: (obj: Str, encoding := Str, errors := Str) -> Bytes
.decode: (obj: Bytes, encoding := Str, errors := Str) -> Str
.lookup: (encoding: Str) -> CodecInfo

.getencoder: (encoding: Str) -> (obj: Str) -> (Bytes, Nat)
.getdecoder: (encoding: Str) -> (obj: Bytes) -> (Str, Nat)

.open!: (filename: Str, mode := Str, encoding := Str, errors := Str, buffering := Int) -> StreamReaderWriter!
.register!: (search_function: (name: Str) -> CodecInfo or NoneType) => NoneType
.unregister!: (search_function: (name: Str) -> CodecInfo or NoneType) => NoneType
Loading

0 comments on commit 559dc63

Please sign in to comment.