Skip to content

Commit

Permalink
Merge pull request #460 from erg-lang/fix-match
Browse files Browse the repository at this point in the history
Improve pattern matching mechanism
  • Loading branch information
mtshiba committed Sep 27, 2023
2 parents 1c569ec + bbac0a3 commit 475eca9
Show file tree
Hide file tree
Showing 12 changed files with 745 additions and 373 deletions.
5 changes: 5 additions & 0 deletions crates/erg_common/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,11 @@ pub trait Stream<T>: Sized {
fn retain(&mut self, f: impl FnMut(&T) -> bool) {
self.ref_mut_payload().retain(f);
}

fn concat(mut self, other: Self) -> Self {
self.extend(other.payload());
self
}
}

#[macro_export]
Expand Down
264 changes: 131 additions & 133 deletions crates/erg_compiler/codegen.rs

Large diffs are not rendered by default.

45 changes: 22 additions & 23 deletions crates/erg_compiler/context/initialize/funcs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,14 @@ impl Context {
poly(FROZENSET, vec![ty_tp(T.clone())]),
)
.quantify();
let getattr_t = func(
vec![kw(KW_OBJ, Obj), kw(KW_NAME, Str)],
None,
vec![kw_default(KW_DEFAULT, T.clone(), Obj)],
T.clone(),
)
.quantify();
let hasattr_t = func(vec![kw(KW_OBJ, Obj), kw(KW_NAME, Str)], None, vec![], Bool);
let t_hash = func1(mono(HASH), Int);
let t_if = func(
vec![
Expand Down Expand Up @@ -349,6 +357,20 @@ impl Context {
Some(FUNC_FILTER),
);
self.register_builtin_py_impl(FUNC_FROZENSET, t_frozenset, Immutable, vis.clone(), None);
self.register_builtin_py_impl(
FUNC_GETATTR,
getattr_t,
Immutable,
vis.clone(),
Some(FUNC_GETATTR),
);
self.register_builtin_py_impl(
FUNC_HASATTR,
hasattr_t,
Immutable,
vis.clone(),
Some(FUNC_HASATTR),
);
self.register_builtin_py_impl(FUNC_HASH, t_hash, Immutable, vis.clone(), Some(FUNC_HASH));
self.register_builtin_py_impl(
FUNC_ISINSTANCE,
Expand Down Expand Up @@ -644,29 +666,6 @@ impl Context {
}

pub(super) fn init_builtin_py_specific_funcs(&mut self) {
let hasattr_t = func(vec![kw(KW_OBJ, Obj), kw(KW_NAME, Str)], None, vec![], Bool);
self.register_builtin_py_impl(
FUNC_HASATTR,
hasattr_t,
Immutable,
Visibility::BUILTIN_PUBLIC,
None,
);
let T = type_q("T");
let getattr_t = func(
vec![kw(KW_OBJ, Obj), kw(KW_NAME, Str)],
None,
vec![kw_default(KW_DEFAULT, T.clone(), Obj)],
T,
)
.quantify();
self.register_builtin_py_impl(
FUNC_GETATTR,
getattr_t,
Immutable,
Visibility::BUILTIN_PUBLIC,
None,
);
let setattr_t = func(
vec![kw(KW_OBJ, Obj), kw(KW_NAME, Str), kw(KW_VALUE, Obj)],
None,
Expand Down
45 changes: 42 additions & 3 deletions crates/erg_compiler/declare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,8 +236,19 @@ impl ASTLowerer {
Ok(args)
}

fn fake_lower_call(&self, call: ast::Call) -> LowerResult<hir::Call> {
fn fake_lower_call(&self, mut call: ast::Call) -> LowerResult<hir::Call> {
let obj = self.fake_lower_expr(*call.obj)?;
if call
.attr_name
.as_ref()
.is_some_and(|attr| attr.inspect() == "__Tuple_getitem__")
{
call.attr_name
.as_mut()
.unwrap()
.name
.rename("__getitem__".into());
}
let attr_name = call.attr_name.map(hir::Identifier::bare);
let args = self.fake_lower_args(call.args)?;
Ok(hir::Call::new(obj, attr_name, args))
Expand Down Expand Up @@ -428,7 +439,7 @@ impl ASTLowerer {
}

fn fake_lower_params(&self, params: ast::Params) -> LowerResult<hir::Params> {
let (non_defaults_, var_params_, defaults_, parens) = params.deconstruct();
let (non_defaults_, var_params_, defaults_, guards_, parens) = params.deconstruct();
let mut non_defaults = vec![];
for non_default_ in non_defaults_.into_iter() {
let t_spec_as_expr = non_default_
Expand Down Expand Up @@ -474,7 +485,23 @@ impl ASTLowerer {
let default = hir::DefaultParamSignature::new(sig, default_val);
defaults.push(default);
}
Ok(hir::Params::new(non_defaults, var_params, defaults, parens))
let mut guards = vec![];
for guard in guards_.into_iter() {
let guard = match guard {
ast::GuardClause::Condition(cond) => {
hir::GuardClause::Condition(self.fake_lower_expr(cond)?)
}
ast::GuardClause::Bind(bind) => hir::GuardClause::Bind(self.fake_lower_def(bind)?),
};
guards.push(guard);
}
Ok(hir::Params::new(
non_defaults,
var_params,
defaults,
guards,
parens,
))
}

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

fn fake_lower_compound(&self, compound: ast::Compound) -> LowerResult<hir::Block> {
let mut chunks = vec![];
for chunk in compound.into_iter() {
let chunk = self.fake_lower_expr(chunk)?;
chunks.push(chunk);
}
Ok(hir::Block::new(chunks))
}

pub(crate) fn fake_lower_expr(&self, expr: ast::Expr) -> LowerResult<hir::Expr> {
match expr {
ast::Expr::Literal(lit) => Ok(hir::Expr::Literal(self.fake_lower_literal(lit)?)),
Expand All @@ -532,6 +568,9 @@ impl ASTLowerer {
ast::Expr::Accessor(acc) => Ok(hir::Expr::Accessor(self.fake_lower_acc(acc)?)),
ast::Expr::Call(call) => Ok(hir::Expr::Call(self.fake_lower_call(call)?)),
ast::Expr::Lambda(lambda) => Ok(hir::Expr::Lambda(self.fake_lower_lambda(lambda)?)),
ast::Expr::Compound(compound) => {
Ok(hir::Expr::Compound(self.fake_lower_compound(compound)?))
}
ast::Expr::Dummy(dummy) => Ok(hir::Expr::Dummy(self.fake_lower_dummy(dummy)?)),
ast::Expr::TypeAscription(tasc) => {
Ok(hir::Expr::TypeAsc(self.fake_lower_type_asc(tasc)?))
Expand Down
60 changes: 48 additions & 12 deletions crates/erg_compiler/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ use erg_common::log;
use erg_common::set::Set as HashSet;
use erg_common::traits::{Locational, NestedDisplay, NoTypeDisplay, Stream};
use erg_common::{
enum_unwrap, fmt_option, fmt_vec, impl_display_for_enum, impl_display_from_nested,
impl_locational, impl_locational_for_enum, impl_nested_display_for_chunk_enum,
impl_nested_display_for_enum, impl_no_type_display_for_enum, impl_stream,
enum_unwrap, fmt_option, fmt_vec, fmt_vec_split_with, impl_display_for_enum,
impl_display_from_nested, impl_locational, impl_locational_for_enum,
impl_nested_display_for_chunk_enum, impl_nested_display_for_enum,
impl_no_type_display_for_enum, impl_stream,
};
use erg_common::{impl_from_trait_for_enum, impl_try_from_trait_for_enum, Str};

Expand Down Expand Up @@ -1220,11 +1221,12 @@ pub struct BinOp {
}

impl NestedDisplay for BinOp {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result {
writeln!(f, "`{}`(: {}):", self.op.content, self.info.t)?;
self.lhs.fmt_nest(f, level + 1)?;
writeln!(f)?;
self.rhs.fmt_nest(f, level + 1)
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
write!(
f,
"`{}`(: {})({}, {})",
self.op.content, self.info.t, self.lhs, self.rhs
)
}
}

Expand Down Expand Up @@ -1734,11 +1736,38 @@ impl DefaultParamSignature {
}
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum GuardClause {
Condition(Expr),
Bind(Def),
}

impl NestedDisplay for GuardClause {
fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, _level: usize) -> std::fmt::Result {
match self {
GuardClause::Condition(cond) => write!(f, "{}", cond),
GuardClause::Bind(bind) => write!(f, "{}", bind),
}
}
}

impl NoTypeDisplay for GuardClause {
fn to_string_notype(&self) -> String {
match self {
GuardClause::Condition(cond) => cond.to_string_notype(),
GuardClause::Bind(bind) => bind.to_string_notype(),
}
}
}

impl_display_from_nested!(GuardClause);

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Params {
pub non_defaults: Vec<NonDefaultParamSignature>,
pub var_params: Option<Box<NonDefaultParamSignature>>,
pub defaults: Vec<DefaultParamSignature>,
pub guards: Vec<GuardClause>,
pub parens: Option<(Token, Token)>,
}

Expand All @@ -1749,8 +1778,13 @@ impl fmt::Display for Params {
"({}, {}, {})",
fmt_vec(&self.non_defaults),
fmt_option!(pre "*", &self.var_params),
fmt_vec(&self.defaults)
)
fmt_vec(&self.defaults),
)?;
if !self.guards.is_empty() {
write!(f, " if {}", fmt_vec_split_with(&self.guards, " and "))
} else {
Ok(())
}
}
}

Expand Down Expand Up @@ -1811,22 +1845,24 @@ impl Params {
non_defaults: Vec<NonDefaultParamSignature>,
var_params: Option<Box<NonDefaultParamSignature>>,
defaults: Vec<DefaultParamSignature>,
guards: Vec<GuardClause>,
parens: Option<(Token, Token)>,
) -> Self {
Self {
non_defaults,
var_params,
defaults,
guards,
parens,
}
}

pub fn empty() -> Self {
Self::new(vec![], None, vec![], None)
Self::new(vec![], None, vec![], vec![], None)
}

pub fn single(sig: NonDefaultParamSignature) -> Self {
Self::new(vec![sig], None, vec![], None)
Self::new(vec![sig], None, vec![], vec![], None)
}

pub const fn ref_deconstruct(&self) -> RefRawParams {
Expand Down
38 changes: 31 additions & 7 deletions crates/erg_compiler/lib/std/semver.er
Original file line number Diff line number Diff line change
@@ -1,13 +1,35 @@
# e.g. `nightly.0`
.Identifier = Class { .name = Str; .num = Nat }
.Identifier|<: Show|.
__str__ ref self = "\{self.name}.\{self.num}"
.Identifier|.Identifier <: Eq|.
__eq__ self, other: .Identifier =
self.name == other.name and self.num == other.num
.Identifier.
from_str s: Str =
match s.split("."):
[name, num] ->
num_ = nat(num)
assert num_ in Nat
.Identifier::__new__ { .name; .num = num_ }
_ -> panic "invalid identifier string: \{s}"

.Version = Class { .major = Nat; .minor = Nat; .patch = Nat; .pre = .Identifier or NoneType }
.Version.
.SemVer = Class { .major = Nat; .minor = Nat; .patch = Nat; .pre = .Identifier or NoneType }
.SemVer|<: Show|.
__str__ ref self =
if self.pre != None:
do: "SemVer(\{self.major}.\{self.minor}.\{self.patch}-\{self.pre})"
do: "SemVer(\{self.major}.\{self.minor}.\{self.patch})"
.SemVer.
new major, minor, patch, pre := None =
.Version::__new__ { .major = major; .minor = minor; .patch = patch; .pre = pre }
.SemVer::__new__ { .major; .minor; .patch; .pre }
from_str s: Str =
match s.split("."):
[major, minor, patch] ->
.SemVer.new(nat(major), nat(minor), nat(patch))
[major, minor, patch, pre] ->
.SemVer.new(nat(major), nat(minor), nat(patch), .Identifier.from_str(pre))
_ -> panic "invalid semver string: \{s}"
#[
greater self, other: .Version =
match [self.major > other.major, self.major >= other.major, self.minor > other.minor, self.minor >= other.minor, self.patch > other.patch]:
Expand All @@ -16,12 +38,14 @@
[_, True, _, True, True] -> True
_ -> False
]#
.Version|.Version <: Eq|.
__eq__ self, other: .Version =
.SemVer|<: Eq|.
__eq__ self, other: .SemVer =
self.major == other.major and self.minor == other.minor and self.patch == other.patch and self.pre == other.pre

if! __name__ == "__main__", do!:
v = .Version.new(0, 0, 1)
v = .SemVer.new(0, 0, 1)
assert v.minor == 0
assert v.pre == None
assert v != .Version.new(0, 0, 2)
assert v != .SemVer.new(0, 0, 2)
v2 = .SemVer.from_str("0.0.1")
assert v == v2
Loading

0 comments on commit 475eca9

Please sign in to comment.