chore: improve pattern match

This commit is contained in:
Shunsuke Shibayama 2023-09-27 11:59:20 +09:00
parent 5c757b83f5
commit f561eebc2f
9 changed files with 343 additions and 125 deletions

View file

@ -84,6 +84,7 @@ fn escape_name(name: &str, vis: &VisibilityModifier, def_line: u32, def_col: u32
};
Str::from(format!("::{name}{line_mangling}"))
} else {
// For public APIs, mangling is not performed because `hasattr`, etc. cannot be used.
Str::from(name)
}
}
@ -349,6 +350,7 @@ impl PyCodeGenerator {
}
/// swap TOS and TOS1
#[allow(unused)]
fn rot2(&mut self) {
if self.py_version.minor >= Some(11) {
self.write_instr(Opcode311::SWAP);
@ -359,6 +361,7 @@ impl PyCodeGenerator {
}
}
#[allow(unused)]
fn dup_top(&mut self) {
if self.py_version.minor >= Some(11) {
self.write_instr(Opcode311::COPY);
@ -2102,63 +2105,47 @@ impl PyCodeGenerator {
pre_block: Block,
is_last_arm: bool,
) -> Option<usize> {
log!(info "entered {}", fn_name!());
let param = params.non_defaults.remove(0);
log!(info "entered {}({param})", fn_name!());
// for pre_block
match &param.raw.pat {
ParamPattern::VarName(name) => {
let ident = erg_parser::ast::Identifier::private_from_varname(name.clone());
let ident = Identifier::new(ident, None, param.vi.clone());
self.emit_store_instr(ident.clone(), AccessKind::Name);
self.emit_load_name_instr(ident);
let ident = Identifier::new(ident, None, param.vi);
self.emit_store_instr(ident, AccessKind::Name);
}
ParamPattern::Discard(_) => {
self.emit_pop_top();
}
ParamPattern::Discard(_) => {}
_other => unreachable!(),
}
self.emit_frameless_block(pre_block, vec![]);
let mut pop_jump_point = None;
// If it's the last arm, there's no need to inspect it
match param.t_spec_as_expr {
Some(t_spec) if !is_last_arm => {
// < v3.11:
// arg
// ↓ LOAD_NAME(contains_operator)
// arg contains_operator
// ↓ ROT_TWO
// contains_operator arg
// ↓ load expr
// contains_operator arg expr
//
// in v3.11:
// arg null
// ↓ SWAP 1
// null arg
// ↓ LOAD_NAME(contains_operator)
// null arg contains_operator
// ↓ SWAP 1
// null contains_operator arg
// ↓ load expr
// null contains_operator arg expr
// ↓ SWAP 1
// null contains_operator expr arg
if self.py_version.minor >= Some(11) {
self.emit_push_null();
self.rot2();
if !is_last_arm {
let last = params.guards.len().saturating_sub(1);
for (i, mut guard) in params.guards.into_iter().enumerate() {
if let Expr::BinOp(BinOp {
op:
Token {
kind: TokenKind::ContainsOp,
..
},
lhs: _,
rhs,
..
}) = &mut guard
{
// *lhs.ref_mut_t().unwrap() = Type::Obj;
*rhs.ref_mut_t().unwrap() = Type::Obj;
}
if !self.contains_op_loaded {
self.load_contains_op();
self.emit_expr(guard);
if i != 0 {
self.emit_binop_instr(
Token::from_str(TokenKind::AndOp, "and"),
TypePair::Others,
);
}
self.emit_load_name_instr(Identifier::private("#contains_operator"));
self.rot2();
self.emit_expr(t_spec);
self.rot2();
if self.py_version.minor >= Some(11) {
self.emit_precall_and_call(2);
} else {
self.write_instr(Opcode310::CALL_FUNCTION);
self.write_arg(2);
}
self.stack_dec();
if i == last {
pop_jump_point = Some(self.lasti());
// HACK: match branches often jump very far (beyond the u8 range),
// so the jump destination should be reserved as the u16 range.
@ -2169,20 +2156,10 @@ impl PyCodeGenerator {
// but the numbers are the same, only the way the jumping points are calculated is different.
self.write_instr(Opcode310::POP_JUMP_IF_FALSE); // jump to the next case
self.write_arg(0);
self.stack_dec();
// if matched, pop original
self.emit_pop_top(); // self.stack_dec();
}
_ => {}
}
match param.raw.pat {
ParamPattern::VarName(name) => {
let ident = erg_parser::ast::Identifier::private_from_varname(name);
let ident = Identifier::new(ident, None, param.vi);
self.emit_store_instr(ident, AccessKind::Name);
}
ParamPattern::Discard(_) => {
self.emit_pop_top();
}
_other => unreachable!(),
}
pop_jump_point
}
@ -3123,13 +3100,13 @@ impl PyCodeGenerator {
/// forブロックなどで使う
fn emit_frameless_block(&mut self, block: Block, params: Vec<Str>) {
log!(info "entered {}", fn_name!());
if block.is_empty() {
return;
}
let line = block.ln_begin().unwrap_or(0);
for param in params {
self.emit_store_instr(Identifier::public_with_line(DOT, param, line), Name);
}
if block.is_empty() {
return;
}
let init_stack_len = self.stack_len();
for chunk in block.into_iter() {
self.emit_chunk(chunk);
@ -3253,7 +3230,7 @@ impl PyCodeGenerator {
"?".into(),
);
let param = NonDefaultParamSignature::new(raw, vi, None);
let params = Params::new(vec![self_param, param], None, vec![], None);
let params = Params::new(vec![self_param, param], None, vec![], vec![], None);
(param_name, params)
} else {
("_".into(), Params::single(self_param))

View file

@ -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![
@ -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,
@ -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,

View file

@ -241,8 +241,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))
@ -434,7 +445,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_
@ -480,7 +491,18 @@ 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 = self.fake_lower_expr(guard)?;
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> {

View file

@ -1739,6 +1739,7 @@ pub struct Params {
pub non_defaults: Vec<NonDefaultParamSignature>,
pub var_params: Option<Box<NonDefaultParamSignature>>,
pub defaults: Vec<DefaultParamSignature>,
pub guards: Vec<Expr>,
pub parens: Option<(Token, Token)>,
}
@ -1811,22 +1812,24 @@ impl Params {
non_defaults: Vec<NonDefaultParamSignature>,
var_params: Option<Box<NonDefaultParamSignature>>,
defaults: Vec<DefaultParamSignature>,
guards: Vec<Expr>,
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 {

View file

@ -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]:
@ -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

View file

@ -1344,6 +1344,7 @@ impl ASTLowerer {
hir_non_defaults,
hir_var_params,
hir_defaults,
vec![],
params.parens,
);
if let Err(errs) = self
@ -1353,6 +1354,18 @@ impl ASTLowerer {
{
self.errs.extend(errs);
}
for guard in params.guards.into_iter() {
match self.fake_lower_expr(guard) {
Ok(guard) => {
if hir_params.guards.contains(&guard) {
log!(err "duplicate guard: {guard}");
continue;
}
hir_params.guards.push(guard)
}
Err(es) => self.errs.extend(es),
}
}
if !errs.is_empty() {
Err(errs)
} else {

View file

@ -94,6 +94,11 @@ impl Literal {
Self { token }
}
pub fn str(s: impl Into<Str>, line: u32) -> Self {
let token = Token::new_fake(TokenKind::StrLit, s, line, 0, 0);
Self { token }
}
#[inline]
pub fn is(&self, kind: TokenKind) -> bool {
self.token.is(kind)
@ -3165,6 +3170,10 @@ impl VarName {
self.0.content.starts_with('\'')
}
pub fn is_generated(&self) -> bool {
self.0.content.starts_with('%')
}
pub const fn token(&self) -> &Token {
&self.0
}
@ -3999,7 +4008,9 @@ impl TryFrom<&ParamPattern> for Expr {
fn try_from(value: &ParamPattern) -> Result<Self, Self::Error> {
match value {
// ParamPattern::Discard(token) => Ok(Expr::Accessor(Accessor::local(token.clone()))),
ParamPattern::VarName(name) => Ok(Expr::Accessor(Accessor::local(name.0.clone()))),
ParamPattern::VarName(name) if name.inspect() != "_" => {
Ok(Expr::Accessor(Accessor::local(name.0.clone())))
}
ParamPattern::Lit(lit) => Ok(Expr::Literal(lit.clone())),
ParamPattern::Array(array) => Expr::try_from(array),
ParamPattern::Tuple(tuple) => Expr::try_from(tuple),
@ -4122,6 +4133,8 @@ pub struct Params {
pub non_defaults: Vec<NonDefaultParamSignature>,
pub var_params: Option<Box<NonDefaultParamSignature>>,
pub defaults: Vec<DefaultParamSignature>,
/// match conditions
pub guards: Vec<Expr>,
pub parens: Option<(Token, Token)>,
}
@ -4134,6 +4147,15 @@ impl fmt::Display for Params {
if !self.defaults.is_empty() {
write!(f, ", {}", fmt_vec(&self.defaults))?;
}
if !self.guards.is_empty() {
write!(f, " if ")?;
}
for (i, guard) in self.guards.iter().enumerate() {
if i > 0 {
write!(f, " and ")?;
}
write!(f, "{guard}")?;
}
write!(f, ")")
}
}
@ -4166,6 +4188,7 @@ type RawParams = (
Vec<NonDefaultParamSignature>,
Option<Box<NonDefaultParamSignature>>,
Vec<DefaultParamSignature>,
Vec<Expr>,
Option<(Token, Token)>,
);
@ -4180,6 +4203,7 @@ impl Params {
non_defaults,
var_params: var_params.map(Box::new),
defaults,
guards: Vec::new(),
parens,
}
}
@ -4193,6 +4217,7 @@ impl Params {
self.non_defaults,
self.var_params,
self.defaults,
self.guards,
self.parens,
)
}
@ -4206,6 +4231,14 @@ impl Params {
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn add_guard(&mut self, guard: Expr) {
self.guards.push(guard);
}
pub fn extend_guards(&mut self, guards: Vec<Expr>) {
self.guards.extend(guards);
}
}
/// 引数を取るならTypeでもSubr扱い

View file

@ -453,8 +453,13 @@ impl Desugarer {
..default
});
}
let mut guards = vec![];
for guard in params.guards.into_iter() {
guards.push(desugar(guard));
}
params.non_defaults = non_defaults;
params.defaults = defaults;
params.guards = guards;
params
}
@ -827,15 +832,17 @@ impl Desugarer {
}
fn desugar_params_patterns(&mut self, params: &mut Params, pre_block: &mut Block) {
let mut guards = vec![];
for param in params.non_defaults.iter_mut() {
self.desugar_nd_param(param, pre_block);
guards.extend(self.desugar_nd_param(param, pre_block));
}
if let Some(var_params) = params.var_params.as_mut() {
self.desugar_nd_param(var_params, pre_block);
guards.extend(self.desugar_nd_param(var_params, pre_block));
}
for param in params.defaults.iter_mut() {
self.desugar_nd_param(&mut param.sig, pre_block);
guards.extend(self.desugar_nd_param(&mut param.sig, pre_block));
}
params.extend_guards(guards);
}
fn desugar_nested_var_pattern(
@ -1024,6 +1031,72 @@ impl Desugarer {
Expr::from(NormalSet::new(l_brace, r_brace, args))
}
fn len_guard(param_name: Str, n: usize, loc: &impl Locational) -> Expr {
let name = VarName::new(Token::new_fake(
TokenKind::Symbol,
param_name.clone(),
loc.ln_begin().unwrap_or(1),
loc.col_begin().unwrap_or(0),
loc.col_end().unwrap_or(0),
));
let eq = Token::from_str(TokenKind::DblEq, "==");
let len = Literal::nat(n, loc.ln_begin().unwrap_or(0));
Expr::from(
Identifier::private("len".into())
.call1(Expr::from(Identifier::private_from_varname(name))),
)
.bin_op(eq, len.into())
.into()
}
fn hasattr_guard<'i>(
param_name: Str,
mut keys: impl Iterator<Item = &'i Identifier>,
loc: &impl Locational,
) -> Option<Expr> {
let name = VarName::new(Token::new_fake(
TokenKind::Symbol,
param_name.clone(),
loc.ln_begin().unwrap_or(1),
loc.col_begin().unwrap_or(0),
loc.col_end().unwrap_or(0),
));
let name = Expr::from(Identifier::private_from_varname(name));
let Some(key) = keys.next() else {
return None;
};
let attr_name = Expr::from(Literal::str(
format!("\"{}\"", key.inspect().clone()),
key.ln_begin().unwrap_or(0),
));
let hasattr = Identifier::private("hasattr".into()).call2(name.clone(), attr_name);
let res = keys.fold(Expr::from(hasattr), |acc, key| {
let attr_name = Expr::from(Literal::str(
format!("\"{}\"", key.inspect().clone()),
key.ln_begin().unwrap_or(0),
));
let hasattr = Identifier::private("hasattr".into()).call2(name.clone(), attr_name);
acc.bin_op(Token::from_str(TokenKind::AndOp, "and"), hasattr.into())
.into()
});
Some(res)
}
fn type_guard(param_name: Str, class: &Expr, loc: &impl Locational) -> Option<Expr> {
let name = VarName::new(Token::new_fake(
TokenKind::Symbol,
param_name.clone(),
loc.ln_begin().unwrap_or(1),
loc.col_begin().unwrap_or(0),
loc.col_end().unwrap_or(0),
));
let in_op = class.clone().bin_op(
Token::dummy(TokenKind::ContainsOp, "contains"),
Identifier::private_from_varname(name).into(),
);
Some(in_op.into())
}
/// ```erg
/// f [x, y] =
/// ...
@ -1056,10 +1129,24 @@ impl Desugarer {
/// ```erg
/// f _: {1}, _: {2} = ...
/// ```
fn desugar_nd_param(&mut self, param: &mut NonDefaultParamSignature, pre_block: &mut Block) {
fn desugar_nd_param(
&mut self,
param: &mut NonDefaultParamSignature,
pre_block: &mut Block,
) -> Vec<Expr> {
let mut guards = vec![];
let line = param.ln_begin().unwrap_or(1);
match &mut param.pat {
ParamPattern::VarName(_v) => {}
ParamPattern::VarName(v) => {
if let Some(t_spec) = param
.t_spec
.as_ref()
.map(|t_spec| t_spec.t_spec_as_expr.as_ref())
{
guards.extend(Self::type_guard(v.inspect().clone(), t_spec, v));
}
guards
}
ParamPattern::Lit(l) => {
let lit = l.clone();
let name = VarName::new(Token::new_fake(
@ -1069,6 +1156,10 @@ impl Desugarer {
l.col_begin().unwrap_or(0),
l.col_end().unwrap_or(0),
));
let eq = Token::from_str(TokenKind::DblEq, "==");
let guard = Expr::from(Identifier::private_from_varname(name.clone()))
.bin_op(eq, Expr::from(lit.clone()));
guards.push(guard.into());
param.pat = ParamPattern::VarName(name);
let l_brace = Token {
content: "{".into(),
@ -1085,18 +1176,21 @@ impl Desugarer {
let t_spec_as_expr = Expr::from(NormalSet::new(l_brace, r_brace, args));
let t_spec = TypeSpecWithOp::new(COLON, t_spec, t_spec_as_expr);
param.t_spec = Some(t_spec);
guards
}
ParamPattern::Tuple(tup) => {
let (buf_name, buf_param) = self.gen_buf_nd_param(tup.loc());
let mut ty_specs = vec![];
let mut ty_exprs = vec![];
guards.push(Self::len_guard(buf_name.clone(), tup.elems.len(), tup));
for (n, elem) in tup.elems.non_defaults.iter_mut().enumerate() {
self.desugar_nested_param_pattern(
let gs = self.desugar_nested_param_pattern(
pre_block,
elem,
&buf_name,
BufIndex::Tuple(n),
);
guards.extend(gs);
let infer = Token::new_fake(TokenKind::Try, "?", line, 0, 0);
let ty_expr = elem
.t_spec
@ -1127,17 +1221,37 @@ impl Desugarer {
param.t_spec = Some(TypeSpecWithOp::new(COLON, t_spec, t_spec_as_expr));
}
param.pat = buf_param;
guards
}
ParamPattern::Array(arr) => {
let expr = Expr::try_from(&*arr);
fn const_check(expr: &Expr) -> bool {
match &expr {
Expr::Accessor(Accessor::Ident(ident)) => ident.is_const(),
Expr::Array(Array::Normal(arr)) => arr
.elems
.pos_args()
.iter()
.all(|pos| const_check(&pos.expr)),
_ => true,
}
}
let expr = Expr::try_from(&*arr).and_then(|expr| {
if const_check(&expr) {
Ok(expr)
} else {
Err(())
}
});
let (buf_name, buf_param) = self.gen_buf_nd_param(arr.loc());
guards.push(Self::len_guard(buf_name.clone(), arr.elems.len(), arr));
for (n, elem) in arr.elems.non_defaults.iter_mut().enumerate() {
self.desugar_nested_param_pattern(
let gs = self.desugar_nested_param_pattern(
pre_block,
elem,
&buf_name,
BufIndex::Array(n),
);
guards.extend(gs);
}
if param.t_spec.is_none() {
let len = arr.elems.non_defaults.len();
@ -1172,16 +1286,19 @@ impl Desugarer {
));
}
param.pat = buf_param;
guards
}
ParamPattern::Record(rec) => {
let (buf_name, buf_param) = self.gen_buf_nd_param(rec.loc());
guards.extend(Self::hasattr_guard(buf_name.clone(), rec.elems.keys(), rec));
for ParamRecordAttr { lhs, rhs } in rec.elems.iter_mut() {
self.desugar_nested_param_pattern(
let gs = self.desugar_nested_param_pattern(
pre_block,
rhs,
&buf_name,
BufIndex::Record(lhs),
);
guards.extend(gs);
}
if param.t_spec.is_none() {
let mut attrs = RecordAttrs::new(vec![]);
@ -1226,6 +1343,7 @@ impl Desugarer {
param.t_spec = Some(TypeSpecWithOp::new(COLON, t_spec, t_spec_as_expr));
}
param.pat = buf_param;
guards
}
/*ParamPattern::DataPack(pack) => {
let (buf_name, buf_sig) = self.gen_buf_name_and_sig(
@ -1243,7 +1361,7 @@ impl Desugarer {
);
}
}*/
_ => {}
_ => guards,
}
}
@ -1253,7 +1371,8 @@ impl Desugarer {
sig: &mut NonDefaultParamSignature,
buf_name: &str,
buf_index: BufIndex,
) {
) -> Vec<Expr> {
let mut guards = vec![];
let obj = Expr::local(
buf_name,
sig.ln_begin().unwrap_or(1),
@ -1282,7 +1401,7 @@ impl Desugarer {
let id = DefId(get_hash(&(&acc, buf_name)));
let block = Block::new(vec![Expr::Accessor(acc)]);
let op = Token::from_str(TokenKind::Assign, "=");
let body = DefBody::new(op, block, id);
let mut body = DefBody::new(op, block, id);
let line = sig.ln_begin().unwrap_or(1);
match &mut sig.pat {
ParamPattern::Tuple(tup) => {
@ -1295,15 +1414,17 @@ impl Desugarer {
)),
body,
)));
guards.push(Self::len_guard(buf_name.clone(), tup.elems.len(), tup));
let mut ty_exprs = vec![];
let mut tys = vec![];
for (n, elem) in tup.elems.non_defaults.iter_mut().enumerate() {
self.desugar_nested_param_pattern(
let gs = self.desugar_nested_param_pattern(
pre_block,
elem,
&buf_name,
BufIndex::Tuple(n),
);
guards.extend(gs);
let infer = Token::new_fake(TokenKind::Try, "?", line, 0, 0);
let ty_expr = elem
.t_spec
@ -1333,6 +1454,7 @@ impl Desugarer {
sig.t_spec = Some(TypeSpecWithOp::new(COLON, t_spec, t_spec_as_expr));
}
sig.pat = buf_sig;
guards
}
ParamPattern::Array(arr) => {
let (buf_name, buf_sig) = self.gen_buf_nd_param(arr.loc());
@ -1343,13 +1465,15 @@ impl Desugarer {
)),
body,
)));
guards.push(Self::len_guard(buf_name.clone(), arr.elems.len(), arr));
for (n, elem) in arr.elems.non_defaults.iter_mut().enumerate() {
self.desugar_nested_param_pattern(
let gs = self.desugar_nested_param_pattern(
pre_block,
elem,
&buf_name,
BufIndex::Array(n),
);
guards.extend(gs);
}
if sig.t_spec.is_none() {
let len = arr.elems.non_defaults.len();
@ -1374,6 +1498,7 @@ impl Desugarer {
));
}
sig.pat = buf_sig;
guards
}
ParamPattern::Record(rec) => {
let (buf_name, buf_sig) = self.gen_buf_nd_param(rec.loc());
@ -1384,6 +1509,7 @@ impl Desugarer {
)),
body,
)));
guards.extend(Self::hasattr_guard(buf_name.clone(), rec.elems.keys(), rec));
let mut attrs = RecordAttrs::new(vec![]);
let mut tys = vec![];
for ParamRecordAttr { lhs, rhs } in rec.elems.iter_mut() {
@ -1391,12 +1517,13 @@ impl Desugarer {
vis: VisModifierSpec::Public(Token::DUMMY),
..lhs.clone()
};
self.desugar_nested_param_pattern(
let gs = self.desugar_nested_param_pattern(
pre_block,
rhs,
&buf_name,
BufIndex::Record(&lhs),
);
guards.extend(gs);
let infer = Token::new_fake(TokenKind::Try, "?", line, 0, 0);
let expr = rhs
.t_spec
@ -1432,6 +1559,7 @@ impl Desugarer {
sig.t_spec = Some(TypeSpecWithOp::new(COLON, t_spec, t_spec_as_expr));
}
sig.pat = buf_sig;
guards
}
/*
VarPattern::DataPack(pack) => {
@ -1450,12 +1578,25 @@ impl Desugarer {
}
*/
ParamPattern::VarName(name) => {
if let Some(t_spec) = sig
.t_spec
.as_ref()
.map(|t_spec| t_spec.t_spec_as_expr.as_ref())
{
guards.extend(Self::type_guard(name.inspect().clone(), t_spec, name));
}
let ident = Identifier::new(VisModifierSpec::Private, name.clone());
let v = VarSignature::new(VarPattern::Ident(ident), sig.t_spec.clone());
let def = Def::new(Signature::Var(v), body);
pre_block.push(Expr::Def(def));
guards
}
ParamPattern::Lit(l) => {
let lhs = body.block.remove(0);
let rhs = Expr::Literal(l.clone());
let eq = Token::new_fake(TokenKind::DblEq, "==", l.ln_begin().unwrap_or(0), 0, 0);
let guard = Expr::BinOp(lhs.bin_op(eq, rhs));
guards.push(guard);
let lit = l.clone();
sig.pat = ParamPattern::VarName(VarName::new(Token::new_fake(
TokenKind::Symbol,
@ -1467,8 +1608,9 @@ impl Desugarer {
let t_spec = TypeSpec::enum_t_spec(vec![lit.clone()]);
let t_spec_as_expr = Self::dummy_set_expr(lit);
sig.t_spec = Some(TypeSpecWithOp::new(COLON, t_spec, t_spec_as_expr));
guards
}
_ => {}
_ => guards,
}
}

View file

@ -572,3 +572,8 @@ fn exec_err_loc() -> Result<(), ()> {
],
)
}
#[test]
fn test_semver() -> Result<(), ()> {
expect_success("crates/erg_compiler/lib/std/semver.er", 0)
}