Skip to content

Commit 475eca9

Browse files
authored
Merge pull request #460 from erg-lang/fix-match
Improve pattern matching mechanism
2 parents 1c569ec + bbac0a3 commit 475eca9

File tree

12 files changed

+745
-373
lines changed

12 files changed

+745
-373
lines changed

crates/erg_common/traits.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,11 @@ pub trait Stream<T>: Sized {
259259
fn retain(&mut self, f: impl FnMut(&T) -> bool) {
260260
self.ref_mut_payload().retain(f);
261261
}
262+
263+
fn concat(mut self, other: Self) -> Self {
264+
self.extend(other.payload());
265+
self
266+
}
262267
}
263268

264269
#[macro_export]

crates/erg_compiler/codegen.rs

Lines changed: 131 additions & 133 deletions
Large diffs are not rendered by default.

crates/erg_compiler/context/initialize/funcs.rs

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,14 @@ impl Context {
116116
poly(FROZENSET, vec![ty_tp(T.clone())]),
117117
)
118118
.quantify();
119+
let getattr_t = func(
120+
vec![kw(KW_OBJ, Obj), kw(KW_NAME, Str)],
121+
None,
122+
vec![kw_default(KW_DEFAULT, T.clone(), Obj)],
123+
T.clone(),
124+
)
125+
.quantify();
126+
let hasattr_t = func(vec![kw(KW_OBJ, Obj), kw(KW_NAME, Str)], None, vec![], Bool);
119127
let t_hash = func1(mono(HASH), Int);
120128
let t_if = func(
121129
vec![
@@ -349,6 +357,20 @@ impl Context {
349357
Some(FUNC_FILTER),
350358
);
351359
self.register_builtin_py_impl(FUNC_FROZENSET, t_frozenset, Immutable, vis.clone(), None);
360+
self.register_builtin_py_impl(
361+
FUNC_GETATTR,
362+
getattr_t,
363+
Immutable,
364+
vis.clone(),
365+
Some(FUNC_GETATTR),
366+
);
367+
self.register_builtin_py_impl(
368+
FUNC_HASATTR,
369+
hasattr_t,
370+
Immutable,
371+
vis.clone(),
372+
Some(FUNC_HASATTR),
373+
);
352374
self.register_builtin_py_impl(FUNC_HASH, t_hash, Immutable, vis.clone(), Some(FUNC_HASH));
353375
self.register_builtin_py_impl(
354376
FUNC_ISINSTANCE,
@@ -644,29 +666,6 @@ impl Context {
644666
}
645667

646668
pub(super) fn init_builtin_py_specific_funcs(&mut self) {
647-
let hasattr_t = func(vec![kw(KW_OBJ, Obj), kw(KW_NAME, Str)], None, vec![], Bool);
648-
self.register_builtin_py_impl(
649-
FUNC_HASATTR,
650-
hasattr_t,
651-
Immutable,
652-
Visibility::BUILTIN_PUBLIC,
653-
None,
654-
);
655-
let T = type_q("T");
656-
let getattr_t = func(
657-
vec![kw(KW_OBJ, Obj), kw(KW_NAME, Str)],
658-
None,
659-
vec![kw_default(KW_DEFAULT, T.clone(), Obj)],
660-
T,
661-
)
662-
.quantify();
663-
self.register_builtin_py_impl(
664-
FUNC_GETATTR,
665-
getattr_t,
666-
Immutable,
667-
Visibility::BUILTIN_PUBLIC,
668-
None,
669-
);
670669
let setattr_t = func(
671670
vec![kw(KW_OBJ, Obj), kw(KW_NAME, Str), kw(KW_VALUE, Obj)],
672671
None,

crates/erg_compiler/declare.rs

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -236,8 +236,19 @@ impl ASTLowerer {
236236
Ok(args)
237237
}
238238

239-
fn fake_lower_call(&self, call: ast::Call) -> LowerResult<hir::Call> {
239+
fn fake_lower_call(&self, mut call: ast::Call) -> LowerResult<hir::Call> {
240240
let obj = self.fake_lower_expr(*call.obj)?;
241+
if call
242+
.attr_name
243+
.as_ref()
244+
.is_some_and(|attr| attr.inspect() == "__Tuple_getitem__")
245+
{
246+
call.attr_name
247+
.as_mut()
248+
.unwrap()
249+
.name
250+
.rename("__getitem__".into());
251+
}
241252
let attr_name = call.attr_name.map(hir::Identifier::bare);
242253
let args = self.fake_lower_args(call.args)?;
243254
Ok(hir::Call::new(obj, attr_name, args))
@@ -428,7 +439,7 @@ impl ASTLowerer {
428439
}
429440

430441
fn fake_lower_params(&self, params: ast::Params) -> LowerResult<hir::Params> {
431-
let (non_defaults_, var_params_, defaults_, parens) = params.deconstruct();
442+
let (non_defaults_, var_params_, defaults_, guards_, parens) = params.deconstruct();
432443
let mut non_defaults = vec![];
433444
for non_default_ in non_defaults_.into_iter() {
434445
let t_spec_as_expr = non_default_
@@ -474,7 +485,23 @@ impl ASTLowerer {
474485
let default = hir::DefaultParamSignature::new(sig, default_val);
475486
defaults.push(default);
476487
}
477-
Ok(hir::Params::new(non_defaults, var_params, defaults, parens))
488+
let mut guards = vec![];
489+
for guard in guards_.into_iter() {
490+
let guard = match guard {
491+
ast::GuardClause::Condition(cond) => {
492+
hir::GuardClause::Condition(self.fake_lower_expr(cond)?)
493+
}
494+
ast::GuardClause::Bind(bind) => hir::GuardClause::Bind(self.fake_lower_def(bind)?),
495+
};
496+
guards.push(guard);
497+
}
498+
Ok(hir::Params::new(
499+
non_defaults,
500+
var_params,
501+
defaults,
502+
guards,
503+
parens,
504+
))
478505
}
479506

480507
fn fake_lower_block(&self, block: ast::Block) -> LowerResult<hir::Block> {
@@ -518,6 +545,15 @@ impl ASTLowerer {
518545
Ok(hir::TypeAscription::new(expr, spec))
519546
}
520547

548+
fn fake_lower_compound(&self, compound: ast::Compound) -> LowerResult<hir::Block> {
549+
let mut chunks = vec![];
550+
for chunk in compound.into_iter() {
551+
let chunk = self.fake_lower_expr(chunk)?;
552+
chunks.push(chunk);
553+
}
554+
Ok(hir::Block::new(chunks))
555+
}
556+
521557
pub(crate) fn fake_lower_expr(&self, expr: ast::Expr) -> LowerResult<hir::Expr> {
522558
match expr {
523559
ast::Expr::Literal(lit) => Ok(hir::Expr::Literal(self.fake_lower_literal(lit)?)),
@@ -532,6 +568,9 @@ impl ASTLowerer {
532568
ast::Expr::Accessor(acc) => Ok(hir::Expr::Accessor(self.fake_lower_acc(acc)?)),
533569
ast::Expr::Call(call) => Ok(hir::Expr::Call(self.fake_lower_call(call)?)),
534570
ast::Expr::Lambda(lambda) => Ok(hir::Expr::Lambda(self.fake_lower_lambda(lambda)?)),
571+
ast::Expr::Compound(compound) => {
572+
Ok(hir::Expr::Compound(self.fake_lower_compound(compound)?))
573+
}
535574
ast::Expr::Dummy(dummy) => Ok(hir::Expr::Dummy(self.fake_lower_dummy(dummy)?)),
536575
ast::Expr::TypeAscription(tasc) => {
537576
Ok(hir::Expr::TypeAsc(self.fake_lower_type_asc(tasc)?))

crates/erg_compiler/hir.rs

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ use erg_common::log;
99
use erg_common::set::Set as HashSet;
1010
use erg_common::traits::{Locational, NestedDisplay, NoTypeDisplay, Stream};
1111
use erg_common::{
12-
enum_unwrap, fmt_option, fmt_vec, impl_display_for_enum, impl_display_from_nested,
13-
impl_locational, impl_locational_for_enum, impl_nested_display_for_chunk_enum,
14-
impl_nested_display_for_enum, impl_no_type_display_for_enum, impl_stream,
12+
enum_unwrap, fmt_option, fmt_vec, fmt_vec_split_with, impl_display_for_enum,
13+
impl_display_from_nested, impl_locational, impl_locational_for_enum,
14+
impl_nested_display_for_chunk_enum, impl_nested_display_for_enum,
15+
impl_no_type_display_for_enum, impl_stream,
1516
};
1617
use erg_common::{impl_from_trait_for_enum, impl_try_from_trait_for_enum, Str};
1718

@@ -1220,11 +1221,12 @@ pub struct BinOp {
12201221
}
12211222

12221223
impl NestedDisplay for BinOp {
1223-
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result {
1224-
writeln!(f, "`{}`(: {}):", self.op.content, self.info.t)?;
1225-
self.lhs.fmt_nest(f, level + 1)?;
1226-
writeln!(f)?;
1227-
self.rhs.fmt_nest(f, level + 1)
1224+
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
1225+
write!(
1226+
f,
1227+
"`{}`(: {})({}, {})",
1228+
self.op.content, self.info.t, self.lhs, self.rhs
1229+
)
12281230
}
12291231
}
12301232

@@ -1734,11 +1736,38 @@ impl DefaultParamSignature {
17341736
}
17351737
}
17361738

1739+
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1740+
pub enum GuardClause {
1741+
Condition(Expr),
1742+
Bind(Def),
1743+
}
1744+
1745+
impl NestedDisplay for GuardClause {
1746+
fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, _level: usize) -> std::fmt::Result {
1747+
match self {
1748+
GuardClause::Condition(cond) => write!(f, "{}", cond),
1749+
GuardClause::Bind(bind) => write!(f, "{}", bind),
1750+
}
1751+
}
1752+
}
1753+
1754+
impl NoTypeDisplay for GuardClause {
1755+
fn to_string_notype(&self) -> String {
1756+
match self {
1757+
GuardClause::Condition(cond) => cond.to_string_notype(),
1758+
GuardClause::Bind(bind) => bind.to_string_notype(),
1759+
}
1760+
}
1761+
}
1762+
1763+
impl_display_from_nested!(GuardClause);
1764+
17371765
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
17381766
pub struct Params {
17391767
pub non_defaults: Vec<NonDefaultParamSignature>,
17401768
pub var_params: Option<Box<NonDefaultParamSignature>>,
17411769
pub defaults: Vec<DefaultParamSignature>,
1770+
pub guards: Vec<GuardClause>,
17421771
pub parens: Option<(Token, Token)>,
17431772
}
17441773

@@ -1749,8 +1778,13 @@ impl fmt::Display for Params {
17491778
"({}, {}, {})",
17501779
fmt_vec(&self.non_defaults),
17511780
fmt_option!(pre "*", &self.var_params),
1752-
fmt_vec(&self.defaults)
1753-
)
1781+
fmt_vec(&self.defaults),
1782+
)?;
1783+
if !self.guards.is_empty() {
1784+
write!(f, " if {}", fmt_vec_split_with(&self.guards, " and "))
1785+
} else {
1786+
Ok(())
1787+
}
17541788
}
17551789
}
17561790

@@ -1811,22 +1845,24 @@ impl Params {
18111845
non_defaults: Vec<NonDefaultParamSignature>,
18121846
var_params: Option<Box<NonDefaultParamSignature>>,
18131847
defaults: Vec<DefaultParamSignature>,
1848+
guards: Vec<GuardClause>,
18141849
parens: Option<(Token, Token)>,
18151850
) -> Self {
18161851
Self {
18171852
non_defaults,
18181853
var_params,
18191854
defaults,
1855+
guards,
18201856
parens,
18211857
}
18221858
}
18231859

18241860
pub fn empty() -> Self {
1825-
Self::new(vec![], None, vec![], None)
1861+
Self::new(vec![], None, vec![], vec![], None)
18261862
}
18271863

18281864
pub fn single(sig: NonDefaultParamSignature) -> Self {
1829-
Self::new(vec![sig], None, vec![], None)
1865+
Self::new(vec![sig], None, vec![], vec![], None)
18301866
}
18311867

18321868
pub const fn ref_deconstruct(&self) -> RefRawParams {
Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,35 @@
11
# e.g. `nightly.0`
22
.Identifier = Class { .name = Str; .num = Nat }
3+
.Identifier|<: Show|.
4+
__str__ ref self = "\{self.name}.\{self.num}"
35
.Identifier|.Identifier <: Eq|.
46
__eq__ self, other: .Identifier =
57
self.name == other.name and self.num == other.num
8+
.Identifier.
9+
from_str s: Str =
10+
match s.split("."):
11+
[name, num] ->
12+
num_ = nat(num)
13+
assert num_ in Nat
14+
.Identifier::__new__ { .name; .num = num_ }
15+
_ -> panic "invalid identifier string: \{s}"
616

7-
.Version = Class { .major = Nat; .minor = Nat; .patch = Nat; .pre = .Identifier or NoneType }
8-
.Version.
17+
.SemVer = Class { .major = Nat; .minor = Nat; .patch = Nat; .pre = .Identifier or NoneType }
18+
.SemVer|<: Show|.
19+
__str__ ref self =
20+
if self.pre != None:
21+
do: "SemVer(\{self.major}.\{self.minor}.\{self.patch}-\{self.pre})"
22+
do: "SemVer(\{self.major}.\{self.minor}.\{self.patch})"
23+
.SemVer.
924
new major, minor, patch, pre := None =
10-
.Version::__new__ { .major = major; .minor = minor; .patch = patch; .pre = pre }
25+
.SemVer::__new__ { .major; .minor; .patch; .pre }
26+
from_str s: Str =
27+
match s.split("."):
28+
[major, minor, patch] ->
29+
.SemVer.new(nat(major), nat(minor), nat(patch))
30+
[major, minor, patch, pre] ->
31+
.SemVer.new(nat(major), nat(minor), nat(patch), .Identifier.from_str(pre))
32+
_ -> panic "invalid semver string: \{s}"
1133
#[
1234
greater self, other: .Version =
1335
match [self.major > other.major, self.major >= other.major, self.minor > other.minor, self.minor >= other.minor, self.patch > other.patch]:
@@ -16,12 +38,14 @@
1638
[_, True, _, True, True] -> True
1739
_ -> False
1840
]#
19-
.Version|.Version <: Eq|.
20-
__eq__ self, other: .Version =
41+
.SemVer|<: Eq|.
42+
__eq__ self, other: .SemVer =
2143
self.major == other.major and self.minor == other.minor and self.patch == other.patch and self.pre == other.pre
2244

2345
if! __name__ == "__main__", do!:
24-
v = .Version.new(0, 0, 1)
46+
v = .SemVer.new(0, 0, 1)
2547
assert v.minor == 0
2648
assert v.pre == None
27-
assert v != .Version.new(0, 0, 2)
49+
assert v != .SemVer.new(0, 0, 2)
50+
v2 = .SemVer.from_str("0.0.1")
51+
assert v == v2

0 commit comments

Comments
 (0)