mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-28 12:14:43 +00:00
chore: improve pattern match
This commit is contained in:
parent
5c757b83f5
commit
f561eebc2f
9 changed files with 343 additions and 125 deletions
|
@ -84,6 +84,7 @@ fn escape_name(name: &str, vis: &VisibilityModifier, def_line: u32, def_col: u32
|
||||||
};
|
};
|
||||||
Str::from(format!("::{name}{line_mangling}"))
|
Str::from(format!("::{name}{line_mangling}"))
|
||||||
} else {
|
} else {
|
||||||
|
// For public APIs, mangling is not performed because `hasattr`, etc. cannot be used.
|
||||||
Str::from(name)
|
Str::from(name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -349,6 +350,7 @@ impl PyCodeGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// swap TOS and TOS1
|
/// swap TOS and TOS1
|
||||||
|
#[allow(unused)]
|
||||||
fn rot2(&mut self) {
|
fn rot2(&mut self) {
|
||||||
if self.py_version.minor >= Some(11) {
|
if self.py_version.minor >= Some(11) {
|
||||||
self.write_instr(Opcode311::SWAP);
|
self.write_instr(Opcode311::SWAP);
|
||||||
|
@ -359,6 +361,7 @@ impl PyCodeGenerator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
fn dup_top(&mut self) {
|
fn dup_top(&mut self) {
|
||||||
if self.py_version.minor >= Some(11) {
|
if self.py_version.minor >= Some(11) {
|
||||||
self.write_instr(Opcode311::COPY);
|
self.write_instr(Opcode311::COPY);
|
||||||
|
@ -2102,80 +2105,12 @@ impl PyCodeGenerator {
|
||||||
pre_block: Block,
|
pre_block: Block,
|
||||||
is_last_arm: bool,
|
is_last_arm: bool,
|
||||||
) -> Option<usize> {
|
) -> Option<usize> {
|
||||||
log!(info "entered {}", fn_name!());
|
|
||||||
let param = params.non_defaults.remove(0);
|
let param = params.non_defaults.remove(0);
|
||||||
|
log!(info "entered {}({param})", fn_name!());
|
||||||
// for pre_block
|
// for pre_block
|
||||||
match ¶m.raw.pat {
|
match ¶m.raw.pat {
|
||||||
ParamPattern::VarName(name) => {
|
ParamPattern::VarName(name) => {
|
||||||
let ident = erg_parser::ast::Identifier::private_from_varname(name.clone());
|
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);
|
|
||||||
}
|
|
||||||
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 !self.contains_op_loaded {
|
|
||||||
self.load_contains_op();
|
|
||||||
}
|
|
||||||
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();
|
|
||||||
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.
|
|
||||||
// Other jump instructions may need to be replaced by this way.
|
|
||||||
self.write_instr(EXTENDED_ARG);
|
|
||||||
self.write_arg(0);
|
|
||||||
// in 3.11, POP_JUMP_IF_FALSE is replaced with POP_JUMP_FORWARD_IF_FALSE
|
|
||||||
// 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();
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
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);
|
let ident = Identifier::new(ident, None, param.vi);
|
||||||
self.emit_store_instr(ident, AccessKind::Name);
|
self.emit_store_instr(ident, AccessKind::Name);
|
||||||
}
|
}
|
||||||
|
@ -2184,6 +2119,48 @@ impl PyCodeGenerator {
|
||||||
}
|
}
|
||||||
_other => unreachable!(),
|
_other => unreachable!(),
|
||||||
}
|
}
|
||||||
|
self.emit_frameless_block(pre_block, vec![]);
|
||||||
|
let mut pop_jump_point = None;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
self.emit_expr(guard);
|
||||||
|
if i != 0 {
|
||||||
|
self.emit_binop_instr(
|
||||||
|
Token::from_str(TokenKind::AndOp, "and"),
|
||||||
|
TypePair::Others,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
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.
|
||||||
|
// Other jump instructions may need to be replaced by this way.
|
||||||
|
self.write_instr(EXTENDED_ARG);
|
||||||
|
self.write_arg(0);
|
||||||
|
// in 3.11, POP_JUMP_IF_FALSE is replaced with POP_JUMP_FORWARD_IF_FALSE
|
||||||
|
// 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);
|
||||||
|
// if matched, pop original
|
||||||
|
self.emit_pop_top(); // self.stack_dec();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
pop_jump_point
|
pop_jump_point
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3123,13 +3100,13 @@ impl PyCodeGenerator {
|
||||||
/// forブロックなどで使う
|
/// forブロックなどで使う
|
||||||
fn emit_frameless_block(&mut self, block: Block, params: Vec<Str>) {
|
fn emit_frameless_block(&mut self, block: Block, params: Vec<Str>) {
|
||||||
log!(info "entered {}", fn_name!());
|
log!(info "entered {}", fn_name!());
|
||||||
if block.is_empty() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let line = block.ln_begin().unwrap_or(0);
|
let line = block.ln_begin().unwrap_or(0);
|
||||||
for param in params {
|
for param in params {
|
||||||
self.emit_store_instr(Identifier::public_with_line(DOT, param, line), Name);
|
self.emit_store_instr(Identifier::public_with_line(DOT, param, line), Name);
|
||||||
}
|
}
|
||||||
|
if block.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let init_stack_len = self.stack_len();
|
let init_stack_len = self.stack_len();
|
||||||
for chunk in block.into_iter() {
|
for chunk in block.into_iter() {
|
||||||
self.emit_chunk(chunk);
|
self.emit_chunk(chunk);
|
||||||
|
@ -3253,7 +3230,7 @@ impl PyCodeGenerator {
|
||||||
"?".into(),
|
"?".into(),
|
||||||
);
|
);
|
||||||
let param = NonDefaultParamSignature::new(raw, vi, None);
|
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)
|
(param_name, params)
|
||||||
} else {
|
} else {
|
||||||
("_".into(), Params::single(self_param))
|
("_".into(), Params::single(self_param))
|
||||||
|
|
|
@ -116,6 +116,14 @@ impl Context {
|
||||||
poly(FROZENSET, vec![ty_tp(T.clone())]),
|
poly(FROZENSET, vec![ty_tp(T.clone())]),
|
||||||
)
|
)
|
||||||
.quantify();
|
.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_hash = func1(mono(HASH), Int);
|
||||||
let t_if = func(
|
let t_if = func(
|
||||||
vec![
|
vec![
|
||||||
|
@ -349,6 +357,20 @@ impl Context {
|
||||||
Some(FUNC_FILTER),
|
Some(FUNC_FILTER),
|
||||||
);
|
);
|
||||||
self.register_builtin_py_impl(FUNC_FROZENSET, t_frozenset, Immutable, vis.clone(), None);
|
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_HASH, t_hash, Immutable, vis.clone(), Some(FUNC_HASH));
|
||||||
self.register_builtin_py_impl(
|
self.register_builtin_py_impl(
|
||||||
FUNC_ISINSTANCE,
|
FUNC_ISINSTANCE,
|
||||||
|
@ -644,29 +666,6 @@ impl Context {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn init_builtin_py_specific_funcs(&mut self) {
|
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(
|
let setattr_t = func(
|
||||||
vec![kw(KW_OBJ, Obj), kw(KW_NAME, Str), kw(KW_VALUE, Obj)],
|
vec![kw(KW_OBJ, Obj), kw(KW_NAME, Str), kw(KW_VALUE, Obj)],
|
||||||
None,
|
None,
|
||||||
|
|
|
@ -241,8 +241,19 @@ impl ASTLowerer {
|
||||||
Ok(args)
|
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)?;
|
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 attr_name = call.attr_name.map(hir::Identifier::bare);
|
||||||
let args = self.fake_lower_args(call.args)?;
|
let args = self.fake_lower_args(call.args)?;
|
||||||
Ok(hir::Call::new(obj, attr_name, 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> {
|
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![];
|
let mut non_defaults = vec![];
|
||||||
for non_default_ in non_defaults_.into_iter() {
|
for non_default_ in non_defaults_.into_iter() {
|
||||||
let t_spec_as_expr = non_default_
|
let t_spec_as_expr = non_default_
|
||||||
|
@ -480,7 +491,18 @@ impl ASTLowerer {
|
||||||
let default = hir::DefaultParamSignature::new(sig, default_val);
|
let default = hir::DefaultParamSignature::new(sig, default_val);
|
||||||
defaults.push(default);
|
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> {
|
fn fake_lower_block(&self, block: ast::Block) -> LowerResult<hir::Block> {
|
||||||
|
|
|
@ -1739,6 +1739,7 @@ pub struct Params {
|
||||||
pub non_defaults: Vec<NonDefaultParamSignature>,
|
pub non_defaults: Vec<NonDefaultParamSignature>,
|
||||||
pub var_params: Option<Box<NonDefaultParamSignature>>,
|
pub var_params: Option<Box<NonDefaultParamSignature>>,
|
||||||
pub defaults: Vec<DefaultParamSignature>,
|
pub defaults: Vec<DefaultParamSignature>,
|
||||||
|
pub guards: Vec<Expr>,
|
||||||
pub parens: Option<(Token, Token)>,
|
pub parens: Option<(Token, Token)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1811,22 +1812,24 @@ impl Params {
|
||||||
non_defaults: Vec<NonDefaultParamSignature>,
|
non_defaults: Vec<NonDefaultParamSignature>,
|
||||||
var_params: Option<Box<NonDefaultParamSignature>>,
|
var_params: Option<Box<NonDefaultParamSignature>>,
|
||||||
defaults: Vec<DefaultParamSignature>,
|
defaults: Vec<DefaultParamSignature>,
|
||||||
|
guards: Vec<Expr>,
|
||||||
parens: Option<(Token, Token)>,
|
parens: Option<(Token, Token)>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
non_defaults,
|
non_defaults,
|
||||||
var_params,
|
var_params,
|
||||||
defaults,
|
defaults,
|
||||||
|
guards,
|
||||||
parens,
|
parens,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn empty() -> Self {
|
pub fn empty() -> Self {
|
||||||
Self::new(vec![], None, vec![], None)
|
Self::new(vec![], None, vec![], vec![], None)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn single(sig: NonDefaultParamSignature) -> Self {
|
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 {
|
pub const fn ref_deconstruct(&self) -> RefRawParams {
|
||||||
|
|
|
@ -1,13 +1,35 @@
|
||||||
# e.g. `nightly.0`
|
# e.g. `nightly.0`
|
||||||
.Identifier = Class { .name = Str; .num = Nat }
|
.Identifier = Class { .name = Str; .num = Nat }
|
||||||
|
.Identifier|<: Show|.
|
||||||
|
__str__ ref self = "\{self.name}.\{self.num}"
|
||||||
.Identifier|.Identifier <: Eq|.
|
.Identifier|.Identifier <: Eq|.
|
||||||
__eq__ self, other: .Identifier =
|
__eq__ self, other: .Identifier =
|
||||||
self.name == other.name and self.num == other.num
|
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 }
|
.SemVer = Class { .major = Nat; .minor = Nat; .patch = Nat; .pre = .Identifier or NoneType }
|
||||||
.Version.
|
.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 =
|
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 =
|
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]:
|
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
|
[_, True, _, True, True] -> True
|
||||||
_ -> False
|
_ -> False
|
||||||
]#
|
]#
|
||||||
.Version|.Version <: Eq|.
|
.SemVer|<: Eq|.
|
||||||
__eq__ self, other: .Version =
|
__eq__ self, other: .SemVer =
|
||||||
self.major == other.major and self.minor == other.minor and self.patch == other.patch and self.pre == other.pre
|
self.major == other.major and self.minor == other.minor and self.patch == other.patch and self.pre == other.pre
|
||||||
|
|
||||||
if! __name__ == "__main__", do!:
|
if! __name__ == "__main__", do!:
|
||||||
v = .Version.new(0, 0, 1)
|
v = .SemVer.new(0, 0, 1)
|
||||||
assert v.minor == 0
|
assert v.minor == 0
|
||||||
assert v.pre == None
|
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
|
||||||
|
|
|
@ -1344,6 +1344,7 @@ impl ASTLowerer {
|
||||||
hir_non_defaults,
|
hir_non_defaults,
|
||||||
hir_var_params,
|
hir_var_params,
|
||||||
hir_defaults,
|
hir_defaults,
|
||||||
|
vec![],
|
||||||
params.parens,
|
params.parens,
|
||||||
);
|
);
|
||||||
if let Err(errs) = self
|
if let Err(errs) = self
|
||||||
|
@ -1353,6 +1354,18 @@ impl ASTLowerer {
|
||||||
{
|
{
|
||||||
self.errs.extend(errs);
|
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() {
|
if !errs.is_empty() {
|
||||||
Err(errs)
|
Err(errs)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -94,6 +94,11 @@ impl Literal {
|
||||||
Self { token }
|
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]
|
#[inline]
|
||||||
pub fn is(&self, kind: TokenKind) -> bool {
|
pub fn is(&self, kind: TokenKind) -> bool {
|
||||||
self.token.is(kind)
|
self.token.is(kind)
|
||||||
|
@ -3165,6 +3170,10 @@ impl VarName {
|
||||||
self.0.content.starts_with('\'')
|
self.0.content.starts_with('\'')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_generated(&self) -> bool {
|
||||||
|
self.0.content.starts_with('%')
|
||||||
|
}
|
||||||
|
|
||||||
pub const fn token(&self) -> &Token {
|
pub const fn token(&self) -> &Token {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
|
@ -3999,7 +4008,9 @@ impl TryFrom<&ParamPattern> for Expr {
|
||||||
fn try_from(value: &ParamPattern) -> Result<Self, Self::Error> {
|
fn try_from(value: &ParamPattern) -> Result<Self, Self::Error> {
|
||||||
match value {
|
match value {
|
||||||
// ParamPattern::Discard(token) => Ok(Expr::Accessor(Accessor::local(token.clone()))),
|
// 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::Lit(lit) => Ok(Expr::Literal(lit.clone())),
|
||||||
ParamPattern::Array(array) => Expr::try_from(array),
|
ParamPattern::Array(array) => Expr::try_from(array),
|
||||||
ParamPattern::Tuple(tuple) => Expr::try_from(tuple),
|
ParamPattern::Tuple(tuple) => Expr::try_from(tuple),
|
||||||
|
@ -4122,6 +4133,8 @@ pub struct Params {
|
||||||
pub non_defaults: Vec<NonDefaultParamSignature>,
|
pub non_defaults: Vec<NonDefaultParamSignature>,
|
||||||
pub var_params: Option<Box<NonDefaultParamSignature>>,
|
pub var_params: Option<Box<NonDefaultParamSignature>>,
|
||||||
pub defaults: Vec<DefaultParamSignature>,
|
pub defaults: Vec<DefaultParamSignature>,
|
||||||
|
/// match conditions
|
||||||
|
pub guards: Vec<Expr>,
|
||||||
pub parens: Option<(Token, Token)>,
|
pub parens: Option<(Token, Token)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4134,6 +4147,15 @@ impl fmt::Display for Params {
|
||||||
if !self.defaults.is_empty() {
|
if !self.defaults.is_empty() {
|
||||||
write!(f, ", {}", fmt_vec(&self.defaults))?;
|
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, ")")
|
write!(f, ")")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4166,6 +4188,7 @@ type RawParams = (
|
||||||
Vec<NonDefaultParamSignature>,
|
Vec<NonDefaultParamSignature>,
|
||||||
Option<Box<NonDefaultParamSignature>>,
|
Option<Box<NonDefaultParamSignature>>,
|
||||||
Vec<DefaultParamSignature>,
|
Vec<DefaultParamSignature>,
|
||||||
|
Vec<Expr>,
|
||||||
Option<(Token, Token)>,
|
Option<(Token, Token)>,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -4180,6 +4203,7 @@ impl Params {
|
||||||
non_defaults,
|
non_defaults,
|
||||||
var_params: var_params.map(Box::new),
|
var_params: var_params.map(Box::new),
|
||||||
defaults,
|
defaults,
|
||||||
|
guards: Vec::new(),
|
||||||
parens,
|
parens,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4193,6 +4217,7 @@ impl Params {
|
||||||
self.non_defaults,
|
self.non_defaults,
|
||||||
self.var_params,
|
self.var_params,
|
||||||
self.defaults,
|
self.defaults,
|
||||||
|
self.guards,
|
||||||
self.parens,
|
self.parens,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -4206,6 +4231,14 @@ impl Params {
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.len() == 0
|
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扱い
|
/// 引数を取るならTypeでもSubr扱い
|
||||||
|
|
|
@ -453,8 +453,13 @@ impl Desugarer {
|
||||||
..default
|
..default
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
let mut guards = vec![];
|
||||||
|
for guard in params.guards.into_iter() {
|
||||||
|
guards.push(desugar(guard));
|
||||||
|
}
|
||||||
params.non_defaults = non_defaults;
|
params.non_defaults = non_defaults;
|
||||||
params.defaults = defaults;
|
params.defaults = defaults;
|
||||||
|
params.guards = guards;
|
||||||
params
|
params
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -827,15 +832,17 @@ impl Desugarer {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn desugar_params_patterns(&mut self, params: &mut Params, pre_block: &mut Block) {
|
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() {
|
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() {
|
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() {
|
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(
|
fn desugar_nested_var_pattern(
|
||||||
|
@ -1024,6 +1031,72 @@ impl Desugarer {
|
||||||
Expr::from(NormalSet::new(l_brace, r_brace, args))
|
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
|
/// ```erg
|
||||||
/// f [x, y] =
|
/// f [x, y] =
|
||||||
/// ...
|
/// ...
|
||||||
|
@ -1056,10 +1129,24 @@ impl Desugarer {
|
||||||
/// ```erg
|
/// ```erg
|
||||||
/// f _: {1}, _: {2} = ...
|
/// 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);
|
let line = param.ln_begin().unwrap_or(1);
|
||||||
match &mut param.pat {
|
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) => {
|
ParamPattern::Lit(l) => {
|
||||||
let lit = l.clone();
|
let lit = l.clone();
|
||||||
let name = VarName::new(Token::new_fake(
|
let name = VarName::new(Token::new_fake(
|
||||||
|
@ -1069,6 +1156,10 @@ impl Desugarer {
|
||||||
l.col_begin().unwrap_or(0),
|
l.col_begin().unwrap_or(0),
|
||||||
l.col_end().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);
|
param.pat = ParamPattern::VarName(name);
|
||||||
let l_brace = Token {
|
let l_brace = Token {
|
||||||
content: "{".into(),
|
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_as_expr = Expr::from(NormalSet::new(l_brace, r_brace, args));
|
||||||
let t_spec = TypeSpecWithOp::new(COLON, t_spec, t_spec_as_expr);
|
let t_spec = TypeSpecWithOp::new(COLON, t_spec, t_spec_as_expr);
|
||||||
param.t_spec = Some(t_spec);
|
param.t_spec = Some(t_spec);
|
||||||
|
guards
|
||||||
}
|
}
|
||||||
ParamPattern::Tuple(tup) => {
|
ParamPattern::Tuple(tup) => {
|
||||||
let (buf_name, buf_param) = self.gen_buf_nd_param(tup.loc());
|
let (buf_name, buf_param) = self.gen_buf_nd_param(tup.loc());
|
||||||
let mut ty_specs = vec![];
|
let mut ty_specs = vec![];
|
||||||
let mut ty_exprs = 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() {
|
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,
|
pre_block,
|
||||||
elem,
|
elem,
|
||||||
&buf_name,
|
&buf_name,
|
||||||
BufIndex::Tuple(n),
|
BufIndex::Tuple(n),
|
||||||
);
|
);
|
||||||
|
guards.extend(gs);
|
||||||
let infer = Token::new_fake(TokenKind::Try, "?", line, 0, 0);
|
let infer = Token::new_fake(TokenKind::Try, "?", line, 0, 0);
|
||||||
let ty_expr = elem
|
let ty_expr = elem
|
||||||
.t_spec
|
.t_spec
|
||||||
|
@ -1127,17 +1221,37 @@ impl Desugarer {
|
||||||
param.t_spec = Some(TypeSpecWithOp::new(COLON, t_spec, t_spec_as_expr));
|
param.t_spec = Some(TypeSpecWithOp::new(COLON, t_spec, t_spec_as_expr));
|
||||||
}
|
}
|
||||||
param.pat = buf_param;
|
param.pat = buf_param;
|
||||||
|
guards
|
||||||
}
|
}
|
||||||
ParamPattern::Array(arr) => {
|
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());
|
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() {
|
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,
|
pre_block,
|
||||||
elem,
|
elem,
|
||||||
&buf_name,
|
&buf_name,
|
||||||
BufIndex::Array(n),
|
BufIndex::Array(n),
|
||||||
);
|
);
|
||||||
|
guards.extend(gs);
|
||||||
}
|
}
|
||||||
if param.t_spec.is_none() {
|
if param.t_spec.is_none() {
|
||||||
let len = arr.elems.non_defaults.len();
|
let len = arr.elems.non_defaults.len();
|
||||||
|
@ -1172,16 +1286,19 @@ impl Desugarer {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
param.pat = buf_param;
|
param.pat = buf_param;
|
||||||
|
guards
|
||||||
}
|
}
|
||||||
ParamPattern::Record(rec) => {
|
ParamPattern::Record(rec) => {
|
||||||
let (buf_name, buf_param) = self.gen_buf_nd_param(rec.loc());
|
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() {
|
for ParamRecordAttr { lhs, rhs } in rec.elems.iter_mut() {
|
||||||
self.desugar_nested_param_pattern(
|
let gs = self.desugar_nested_param_pattern(
|
||||||
pre_block,
|
pre_block,
|
||||||
rhs,
|
rhs,
|
||||||
&buf_name,
|
&buf_name,
|
||||||
BufIndex::Record(lhs),
|
BufIndex::Record(lhs),
|
||||||
);
|
);
|
||||||
|
guards.extend(gs);
|
||||||
}
|
}
|
||||||
if param.t_spec.is_none() {
|
if param.t_spec.is_none() {
|
||||||
let mut attrs = RecordAttrs::new(vec![]);
|
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.t_spec = Some(TypeSpecWithOp::new(COLON, t_spec, t_spec_as_expr));
|
||||||
}
|
}
|
||||||
param.pat = buf_param;
|
param.pat = buf_param;
|
||||||
|
guards
|
||||||
}
|
}
|
||||||
/*ParamPattern::DataPack(pack) => {
|
/*ParamPattern::DataPack(pack) => {
|
||||||
let (buf_name, buf_sig) = self.gen_buf_name_and_sig(
|
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,
|
sig: &mut NonDefaultParamSignature,
|
||||||
buf_name: &str,
|
buf_name: &str,
|
||||||
buf_index: BufIndex,
|
buf_index: BufIndex,
|
||||||
) {
|
) -> Vec<Expr> {
|
||||||
|
let mut guards = vec![];
|
||||||
let obj = Expr::local(
|
let obj = Expr::local(
|
||||||
buf_name,
|
buf_name,
|
||||||
sig.ln_begin().unwrap_or(1),
|
sig.ln_begin().unwrap_or(1),
|
||||||
|
@ -1282,7 +1401,7 @@ impl Desugarer {
|
||||||
let id = DefId(get_hash(&(&acc, buf_name)));
|
let id = DefId(get_hash(&(&acc, buf_name)));
|
||||||
let block = Block::new(vec![Expr::Accessor(acc)]);
|
let block = Block::new(vec![Expr::Accessor(acc)]);
|
||||||
let op = Token::from_str(TokenKind::Assign, "=");
|
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);
|
let line = sig.ln_begin().unwrap_or(1);
|
||||||
match &mut sig.pat {
|
match &mut sig.pat {
|
||||||
ParamPattern::Tuple(tup) => {
|
ParamPattern::Tuple(tup) => {
|
||||||
|
@ -1295,15 +1414,17 @@ impl Desugarer {
|
||||||
)),
|
)),
|
||||||
body,
|
body,
|
||||||
)));
|
)));
|
||||||
|
guards.push(Self::len_guard(buf_name.clone(), tup.elems.len(), tup));
|
||||||
let mut ty_exprs = vec![];
|
let mut ty_exprs = vec![];
|
||||||
let mut tys = vec![];
|
let mut tys = vec![];
|
||||||
for (n, elem) in tup.elems.non_defaults.iter_mut().enumerate() {
|
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,
|
pre_block,
|
||||||
elem,
|
elem,
|
||||||
&buf_name,
|
&buf_name,
|
||||||
BufIndex::Tuple(n),
|
BufIndex::Tuple(n),
|
||||||
);
|
);
|
||||||
|
guards.extend(gs);
|
||||||
let infer = Token::new_fake(TokenKind::Try, "?", line, 0, 0);
|
let infer = Token::new_fake(TokenKind::Try, "?", line, 0, 0);
|
||||||
let ty_expr = elem
|
let ty_expr = elem
|
||||||
.t_spec
|
.t_spec
|
||||||
|
@ -1333,6 +1454,7 @@ impl Desugarer {
|
||||||
sig.t_spec = Some(TypeSpecWithOp::new(COLON, t_spec, t_spec_as_expr));
|
sig.t_spec = Some(TypeSpecWithOp::new(COLON, t_spec, t_spec_as_expr));
|
||||||
}
|
}
|
||||||
sig.pat = buf_sig;
|
sig.pat = buf_sig;
|
||||||
|
guards
|
||||||
}
|
}
|
||||||
ParamPattern::Array(arr) => {
|
ParamPattern::Array(arr) => {
|
||||||
let (buf_name, buf_sig) = self.gen_buf_nd_param(arr.loc());
|
let (buf_name, buf_sig) = self.gen_buf_nd_param(arr.loc());
|
||||||
|
@ -1343,13 +1465,15 @@ impl Desugarer {
|
||||||
)),
|
)),
|
||||||
body,
|
body,
|
||||||
)));
|
)));
|
||||||
|
guards.push(Self::len_guard(buf_name.clone(), arr.elems.len(), arr));
|
||||||
for (n, elem) in arr.elems.non_defaults.iter_mut().enumerate() {
|
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,
|
pre_block,
|
||||||
elem,
|
elem,
|
||||||
&buf_name,
|
&buf_name,
|
||||||
BufIndex::Array(n),
|
BufIndex::Array(n),
|
||||||
);
|
);
|
||||||
|
guards.extend(gs);
|
||||||
}
|
}
|
||||||
if sig.t_spec.is_none() {
|
if sig.t_spec.is_none() {
|
||||||
let len = arr.elems.non_defaults.len();
|
let len = arr.elems.non_defaults.len();
|
||||||
|
@ -1374,6 +1498,7 @@ impl Desugarer {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
sig.pat = buf_sig;
|
sig.pat = buf_sig;
|
||||||
|
guards
|
||||||
}
|
}
|
||||||
ParamPattern::Record(rec) => {
|
ParamPattern::Record(rec) => {
|
||||||
let (buf_name, buf_sig) = self.gen_buf_nd_param(rec.loc());
|
let (buf_name, buf_sig) = self.gen_buf_nd_param(rec.loc());
|
||||||
|
@ -1384,6 +1509,7 @@ impl Desugarer {
|
||||||
)),
|
)),
|
||||||
body,
|
body,
|
||||||
)));
|
)));
|
||||||
|
guards.extend(Self::hasattr_guard(buf_name.clone(), rec.elems.keys(), rec));
|
||||||
let mut attrs = RecordAttrs::new(vec![]);
|
let mut attrs = RecordAttrs::new(vec![]);
|
||||||
let mut tys = vec![];
|
let mut tys = vec![];
|
||||||
for ParamRecordAttr { lhs, rhs } in rec.elems.iter_mut() {
|
for ParamRecordAttr { lhs, rhs } in rec.elems.iter_mut() {
|
||||||
|
@ -1391,12 +1517,13 @@ impl Desugarer {
|
||||||
vis: VisModifierSpec::Public(Token::DUMMY),
|
vis: VisModifierSpec::Public(Token::DUMMY),
|
||||||
..lhs.clone()
|
..lhs.clone()
|
||||||
};
|
};
|
||||||
self.desugar_nested_param_pattern(
|
let gs = self.desugar_nested_param_pattern(
|
||||||
pre_block,
|
pre_block,
|
||||||
rhs,
|
rhs,
|
||||||
&buf_name,
|
&buf_name,
|
||||||
BufIndex::Record(&lhs),
|
BufIndex::Record(&lhs),
|
||||||
);
|
);
|
||||||
|
guards.extend(gs);
|
||||||
let infer = Token::new_fake(TokenKind::Try, "?", line, 0, 0);
|
let infer = Token::new_fake(TokenKind::Try, "?", line, 0, 0);
|
||||||
let expr = rhs
|
let expr = rhs
|
||||||
.t_spec
|
.t_spec
|
||||||
|
@ -1432,6 +1559,7 @@ impl Desugarer {
|
||||||
sig.t_spec = Some(TypeSpecWithOp::new(COLON, t_spec, t_spec_as_expr));
|
sig.t_spec = Some(TypeSpecWithOp::new(COLON, t_spec, t_spec_as_expr));
|
||||||
}
|
}
|
||||||
sig.pat = buf_sig;
|
sig.pat = buf_sig;
|
||||||
|
guards
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
VarPattern::DataPack(pack) => {
|
VarPattern::DataPack(pack) => {
|
||||||
|
@ -1450,12 +1578,25 @@ impl Desugarer {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
ParamPattern::VarName(name) => {
|
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 ident = Identifier::new(VisModifierSpec::Private, name.clone());
|
||||||
let v = VarSignature::new(VarPattern::Ident(ident), sig.t_spec.clone());
|
let v = VarSignature::new(VarPattern::Ident(ident), sig.t_spec.clone());
|
||||||
let def = Def::new(Signature::Var(v), body);
|
let def = Def::new(Signature::Var(v), body);
|
||||||
pre_block.push(Expr::Def(def));
|
pre_block.push(Expr::Def(def));
|
||||||
|
guards
|
||||||
}
|
}
|
||||||
ParamPattern::Lit(l) => {
|
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();
|
let lit = l.clone();
|
||||||
sig.pat = ParamPattern::VarName(VarName::new(Token::new_fake(
|
sig.pat = ParamPattern::VarName(VarName::new(Token::new_fake(
|
||||||
TokenKind::Symbol,
|
TokenKind::Symbol,
|
||||||
|
@ -1467,8 +1608,9 @@ impl Desugarer {
|
||||||
let t_spec = TypeSpec::enum_t_spec(vec![lit.clone()]);
|
let t_spec = TypeSpec::enum_t_spec(vec![lit.clone()]);
|
||||||
let t_spec_as_expr = Self::dummy_set_expr(lit);
|
let t_spec_as_expr = Self::dummy_set_expr(lit);
|
||||||
sig.t_spec = Some(TypeSpecWithOp::new(COLON, t_spec, t_spec_as_expr));
|
sig.t_spec = Some(TypeSpecWithOp::new(COLON, t_spec, t_spec_as_expr));
|
||||||
|
guards
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => guards,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -572,3 +572,8 @@ fn exec_err_loc() -> Result<(), ()> {
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_semver() -> Result<(), ()> {
|
||||||
|
expect_success("crates/erg_compiler/lib/std/semver.er", 0)
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue