feat: a lot

This commit is contained in:
2025-08-06 18:30:19 +08:00
parent 32c602f21c
commit f946cb2fd1
22 changed files with 735 additions and 591 deletions

View File

@@ -256,40 +256,6 @@ impl<Ctx: DowngradeContext> Downgrade<Ctx> for ast::Lambda {
let param = downgrade_param(self.param().unwrap(), ctx)?;
let mut body = self.body().unwrap().downgrade(ctx)?;
// Desugar pattern matching in function arguments into a `let` expression.
// For example, `({ a, b ? 2 }): a + b` is desugared into:
// `arg: let a = arg.a; b = arg.b or 2; in a + b`
if let Param::Formals { formals, alias, .. } = &param {
// `Arg` represents the raw argument (the attribute set) passed to the function.
let arg = ctx.new_expr(Hir::Arg(Arg));
let mut bindings: HashMap<_, _> = formals
.iter()
.map(|&(ref k, default)| {
// For each formal parameter, create a `Select` expression to extract it from the argument set.
(
k.clone(),
ctx.new_expr(
Select {
expr: arg,
attrpath: vec![Attr::Str(k.clone())],
default,
}
.to_hir(),
),
)
})
.collect();
// If there's an alias (`... }@alias`), bind the alias name to the raw argument set.
if let Some(alias) = alias {
bindings.insert(
alias.clone(),
ctx.new_expr(Var { sym: alias.clone() }.to_hir()),
);
}
// Wrap the original function body in the new `let` expression.
let let_ = Let { bindings, body };
body = ctx.new_expr(let_.to_hir());
}
let ident;
let required;
let allowed;
@@ -304,22 +270,55 @@ impl<Ctx: DowngradeContext> Downgrade<Ctx> for ast::Lambda {
ellipsis,
alias,
} => {
ident = alias;
ident = alias.clone();
required = Some(
formals
.iter()
.cloned()
.filter(|(_, default)| default.is_none())
.map(|(k, _)| k)
.map(|(k, _)| k.clone())
.collect(),
);
allowed = if ellipsis {
None
} else {
Some(formals.into_iter().map(|(k, _)| k).collect())
Some(formals.iter().map(|(k, _)| k.clone()).collect())
};
// Desugar pattern matching in function arguments into a `let` expression.
// For example, `({ a, b ? 2 }): a + b` is desugared into:
// `arg: let a = arg.a; b = arg.b or 2; in a + b`
let mut bindings: HashMap<_, _> = formals
.into_iter()
.map(|(k, default)| {
// For each formal parameter, create a `Select` expression to extract it from the argument set.
// `Arg` represents the raw argument (the attribute set) passed to the function.
let arg = ctx.new_expr(Hir::Arg(Arg));
(
k.clone(),
ctx.new_expr(
Select {
expr: arg,
attrpath: vec![Attr::Str(k.clone())],
default,
}
.to_hir(),
),
)
})
.collect();
// If there's an alias (`... }@alias`), bind the alias name to the raw argument set.
if let Some(alias) = alias {
bindings.insert(
alias.clone(),
ctx.new_expr(Var { sym: alias.clone() }.to_hir()),
);
}
// Wrap the original function body in the new `let` expression.
let let_ = Let { bindings, body };
body = ctx.new_expr(let_.to_hir());
}
}
let param = ir::Param {
ident,
required,

View File

@@ -40,7 +40,7 @@ pub trait DowngradeContext {
fn with_expr<T>(&self, id: ExprId, f: impl FnOnce(&Hir, &Self) -> T) -> T;
/// Provides temporary mutable access to an expression.
fn with_expr_mut<T>(&mut self, id: ExprId, f: impl FnOnce(&mut Hir, &mut Self) -> T) -> T;
fn with_expr_mut<T>(&mut self, id: &ExprId, f: impl FnOnce(&mut Hir, &mut Self) -> T) -> T;
}
ir! {
@@ -123,7 +123,7 @@ impl Attrs for AttrSet {
match attr {
Attr::Str(ident) => {
// If the next attribute is a static string.
if let Some(&id) = self.stcs.get(&ident) {
if let Some(id) = self.stcs.get(&ident) {
// If a sub-attrset already exists, recurse into it.
ctx.with_expr_mut(id, |expr, ctx| {
expr.as_mut()
@@ -186,7 +186,7 @@ impl Attrs for AttrSet {
}
}
#[derive(Clone, Debug)]
#[derive(Debug)]
enum Param {
/// A simple parameter, e.g., `x: ...`.
Ident(String),

View File

@@ -125,13 +125,13 @@ pub fn downgrade_inherit(
));
}
};
let expr = from.map_or_else(
let expr = from.as_ref().map_or_else(
// If `from` is None, `inherit foo;` becomes `foo = foo;`.
|| Var { sym: ident.clone() }.to_hir(),
// If `from` is Some, `inherit (from) foo;` becomes `foo = from.foo;`.
|expr| {
Select {
expr,
expr: unsafe { expr.clone() },
attrpath: vec![Attr::Str(ident.clone())],
default: None,
}