perf: 捕获判定与upvalue收集合并单入口

This commit is contained in:
2026-10-12 05:33:01 +00:00
parent 9af8f61a23
commit b9ff4226b7
8 changed files with 191 additions and 880 deletions
-507
View File
@@ -1,507 +0,0 @@
//! 闭包捕获分析,父层捕获分析:本函数哪些绑定被任意深度嵌套函数捕获
//! → BTreeMap<String, u8>(cell_idx 按名字排序分配,同一程序重编译得到相同索引,
//! 父 MAKE_CELL 与子函数 upvalue 引用同一 cell)。
use std::collections::{BTreeMap, HashSet};
use oxide_parser::{Declaration, ExportDefaultDeclarationKind, Expression, Statement};
use super::collect_fn_param_names;
use super::names::collect_own_binding_names;
use super::scanner::{
collect_capture_names_expr, collect_capture_names_for_left, collect_capture_names_shadowed,
collect_class_capture_names, CaptureEngine,
};
/// 分析本函数:哪些绑定被任意深度嵌套函数捕获 → captured_bindings。
///
/// 本族以本函数 own 绑定集为过滤条件做捕获集的最终判定;`scanner.rs` 的
/// `collect_capture_names_*` 族带显式 `ref_set`/`shadow`,按过滤条件收集引用名。
pub(crate) fn collect_captured_bindings(
stmts: &[Statement], extra_exprs: &[&oxide_parser::Expression], own: &HashSet<String>,
) -> BTreeMap<String, u8> {
let mut names = HashSet::new();
for stmt in stmts {
collect_captured_stmt(stmt, own, &mut names);
}
// 参数默认值表达式里的引用同样纳入捕获分析:默认值位于函数体之外,其中的
// 嵌套函数引用全局或外层变量时,若未登记进捕获集,发射期会走 LOAD_VAR 读到
// 寄存器残留值。
for expr in extra_exprs {
collect_captured_expr(expr, own, &mut names);
}
// 名字排序分配 cell_idx(稳定跨 run,父 MAKE_CELL 与子 upvalue 统一引用)
let mut sorted: Vec<String> = names.into_iter().collect();
sorted.sort();
sorted.into_iter().enumerate().map(|(i, n)| (n, i as u8)).collect()
}
/// 收集函数参数默认值表达式里的嵌套函数引用(父层 captured/子层 upvalue 判定)。
pub(crate) fn collect_fn_default_captured(
params: &oxide_parser::FormalParameters, own: &HashSet<String>, out: &mut HashSet<String>,
) {
for p in &params.items {
if let Some(init) = &p.initializer {
let mut eng = CaptureEngine::new(own, HashSet::new(), out);
collect_capture_names_expr(init, &mut eng);
}
// 形参模式的运行时求值表达式(计算键/内嵌默认值)在子作用域求值,
// 其标识符引用须纳入父层 MAKE_CELL 判定。
collect_captured_pattern_runtime_exprs(&p.pattern, own, out);
}
}
/// 遍历绑定 pattern 内全部运行时求值表达式(计算键与 AssignmentPattern 默认值):
/// 这些表达式在子作用域(嵌套函数形参绑定时)求值,引用的父层绑定须建 cell 供
/// 子函数 upvalue 读取——与 `collect_capture_names_expr` 同口径(标识符比对)。
pub(crate) fn collect_captured_pattern_runtime_exprs(
pattern: &oxide_parser::BindingPattern, own: &HashSet<String>, out: &mut HashSet<String>,
) {
match pattern {
oxide_parser::BindingPattern::BindingIdentifier(_) => {}
oxide_parser::BindingPattern::ArrayPattern(ap) => {
for p in ap.elements.iter().flatten() {
collect_captured_pattern_runtime_exprs(p, own, out);
}
if let Some(rest) = &ap.rest {
collect_captured_pattern_runtime_exprs(&rest.argument, own, out);
}
}
oxide_parser::BindingPattern::ObjectPattern(op) => {
for prop in &op.properties {
if prop.computed {
let mut eng = CaptureEngine::new(own, HashSet::new(), out);
collect_capture_names_expr(prop.key.to_expression(), &mut eng);
}
collect_captured_pattern_runtime_exprs(&prop.value, own, out);
}
if let Some(rest) = &op.rest {
collect_captured_pattern_runtime_exprs(&rest.argument, own, out);
}
}
oxide_parser::BindingPattern::AssignmentPattern(ap) => {
let mut eng = CaptureEngine::new(own, HashSet::new(), out);
collect_capture_names_expr(&ap.right, &mut eng);
collect_captured_pattern_runtime_exprs(&ap.left, own, out);
}
}
}
/// 只从嵌套函数节点进入扫描(本函数直接引用不算捕获)。
pub(crate) fn collect_captured_stmt(stmt: &Statement, own: &HashSet<String>, out: &mut HashSet<String>) {
match stmt {
Statement::FunctionDeclaration(fd) => {
let body: &[Statement] = fd.body.as_ref().map(|b| &b.statements[..]).unwrap_or(&[]);
collect_fn_default_captured(&fd.params, own, out);
// 函数参数与体内部声明遮蔽父级绑定:体内对这些名字的引用不算捕获父级。
let mut fn_shadow = HashSet::new();
fn_shadow.extend(collect_fn_param_names(&fd.params));
fn_shadow.extend(collect_own_binding_names(&[], body));
let mut eng = CaptureEngine::new(own, fn_shadow, out);
collect_capture_names_shadowed(body, &mut eng);
}
Statement::ClassDeclaration(cd) => {
// 类构造器/方法体与字段表达式引用的父级绑定须建 cell,供子模块 upvalue 捕获。
let mut class_shadow = HashSet::new();
if let Some(id) = &cd.id {
class_shadow.insert(id.name.as_str().to_string());
}
let mut eng = CaptureEngine::new(own, class_shadow, out);
collect_class_capture_names(&cd.body, &mut eng);
}
// export 包裹的变量/函数/类声明:捕获分析须下探声明体,否则被导出函数体内
// 引用模块绑定(含自引用)不会被识别为捕获,闭包内读写退化为隐式全局。
Statement::ExportNamedDeclaration(exp) => {
if let Some(decl) = &exp.declaration {
match decl {
Declaration::VariableDeclaration(vd) => {
for d in &vd.declarations {
collect_captured_binding_keys(&d.id, own, out);
if let Some(init) = &d.init {
collect_captured_expr(init, own, out);
}
}
}
Declaration::FunctionDeclaration(fd) => {
let body: &[Statement] = fd.body.as_ref().map(|b| &b.statements[..]).unwrap_or(&[]);
collect_fn_default_captured(&fd.params, own, out);
let mut fn_shadow = HashSet::new();
fn_shadow.extend(collect_fn_param_names(&fd.params));
fn_shadow.extend(collect_own_binding_names(&[], body));
let mut eng = CaptureEngine::new(own, fn_shadow, out);
collect_capture_names_shadowed(body, &mut eng);
}
Declaration::ClassDeclaration(cd) => {
let mut class_shadow = HashSet::new();
if let Some(id) = &cd.id {
class_shadow.insert(id.name.as_str().to_string());
}
let mut eng = CaptureEngine::new(own, class_shadow, out);
collect_class_capture_names(&cd.body, &mut eng);
}
_ => {}
}
}
}
Statement::ExportDefaultDeclaration(exp) => match &exp.declaration {
ExportDefaultDeclarationKind::FunctionDeclaration(fd) => {
let body: &[Statement] = fd.body.as_ref().map(|b| &b.statements[..]).unwrap_or(&[]);
collect_fn_default_captured(&fd.params, own, out);
let mut fn_shadow = HashSet::new();
fn_shadow.extend(collect_fn_param_names(&fd.params));
fn_shadow.extend(collect_own_binding_names(&[], body));
let mut eng = CaptureEngine::new(own, fn_shadow, out);
collect_capture_names_shadowed(body, &mut eng);
}
ExportDefaultDeclarationKind::ClassDeclaration(cd) => {
let mut class_shadow = HashSet::new();
if let Some(id) = &cd.id {
class_shadow.insert(id.name.as_str().to_string());
}
let mut eng = CaptureEngine::new(own, class_shadow, out);
collect_class_capture_names(&cd.body, &mut eng);
}
other => {
if let Some(e) = other.as_expression() {
collect_captured_expr(e, own, out);
}
}
},
Statement::ExpressionStatement(es) => collect_captured_expr(&es.expression, own, out),
Statement::ReturnStatement(rs) => {
if let Some(a) = &rs.argument {
collect_captured_expr(a, own, out);
}
}
Statement::VariableDeclaration(vd) => {
for d in &vd.declarations {
// 绑定 pattern 的计算键是运行时求值表达式,其引用须纳入捕获判定。
collect_captured_binding_keys(&d.id, own, out);
if let Some(init) = &d.init {
collect_captured_expr(init, own, out);
}
}
}
Statement::IfStatement(is) => {
collect_captured_expr(&is.test, own, out);
collect_captured_stmt(&is.consequent, own, out);
if let Some(alt) = &is.alternate {
collect_captured_stmt(alt, own, out);
}
}
Statement::ForStatement(fs) => {
if let Some(init) = &fs.init {
if let Some(e) = init.as_expression() {
collect_captured_expr(e, own, out);
}
if let oxide_parser::ForStatementInit::VariableDeclaration(vd) = init {
for d in &vd.declarations {
collect_captured_binding_keys(&d.id, own, out);
if let Some(i) = &d.init {
collect_captured_expr(i, own, out);
}
}
}
}
if let Some(t) = &fs.test {
collect_captured_expr(t, own, out);
}
if let Some(u) = &fs.update {
collect_captured_expr(u, own, out);
}
collect_captured_stmt(&fs.body, own, out);
}
Statement::WhileStatement(w) => {
collect_captured_expr(&w.test, own, out);
collect_captured_stmt(&w.body, own, out);
}
Statement::DoWhileStatement(d) => {
collect_captured_stmt(&d.body, own, out);
collect_captured_expr(&d.test, own, out);
}
Statement::ForInStatement(fi) => {
collect_captured_expr(&fi.right, own, out);
if let oxide_parser::ForStatementLeft::VariableDeclaration(vd) = &fi.left {
for d in &vd.declarations {
collect_captured_binding_keys(&d.id, own, out);
}
} else {
// 赋值头是既有绑定引用:头名与默认值表达式须纳入捕获判定。
let mut eng = CaptureEngine::new(own, HashSet::new(), out);
collect_capture_names_for_left(&fi.left, &mut eng);
}
collect_captured_stmt(&fi.body, own, out);
}
Statement::ForOfStatement(fo) => {
collect_captured_expr(&fo.right, own, out);
if let oxide_parser::ForStatementLeft::VariableDeclaration(vd) = &fo.left {
for d in &vd.declarations {
collect_captured_binding_keys(&d.id, own, out);
}
} else {
let mut eng = CaptureEngine::new(own, HashSet::new(), out);
collect_capture_names_for_left(&fo.left, &mut eng);
}
collect_captured_stmt(&fo.body, own, out);
}
Statement::BlockStatement(b) => {
for s in &b.body {
collect_captured_stmt(s, own, out);
}
}
Statement::TryStatement(ts) => {
for s in &ts.block.body {
collect_captured_stmt(s, own, out);
}
if let Some(h) = &ts.handler {
if let Some(param) = &h.param {
collect_captured_binding_pattern(&param.pattern, own, out);
}
for s in &h.body.body {
collect_captured_stmt(s, own, out);
}
}
if let Some(f) = &ts.finalizer {
for s in &f.body {
collect_captured_stmt(s, own, out);
}
}
}
Statement::ThrowStatement(ts) => collect_captured_expr(&ts.argument, own, out),
Statement::SwitchStatement(sw) => {
collect_captured_expr(&sw.discriminant, own, out);
for case in &sw.cases {
for s in &case.consequent {
collect_captured_stmt(s, own, out);
}
}
}
Statement::LabeledStatement(ls) => collect_captured_stmt(&ls.body, own, out),
Statement::WithStatement(ws) => {
collect_captured_expr(&ws.object, own, out);
collect_captured_stmt(&ws.body, own, out);
}
_ => {}
}
}
/// 遍历 catch 参数解构模式内表达式引用(默认值等),供父层 MAKE_CELL 判定。
pub(crate) fn collect_captured_binding_pattern(
pattern: &oxide_parser::BindingPattern, own: &HashSet<String>, out: &mut HashSet<String>,
) {
match pattern {
oxide_parser::BindingPattern::BindingIdentifier(_) => {}
oxide_parser::BindingPattern::ArrayPattern(ap) => {
for p in ap.elements.iter().flatten() {
collect_captured_binding_pattern(p, own, out);
}
if let Some(rest) = &ap.rest {
collect_captured_binding_pattern(&rest.argument, own, out);
}
}
oxide_parser::BindingPattern::ObjectPattern(op) => {
for prop in &op.properties {
// 计算键表达式(本作用域 catch 参数求值,含 IIFE 等嵌套函数)引用
// 本函数绑定走寄存器,只须扫描键内嵌套函数表达式。
if prop.computed {
collect_captured_expr(prop.key.to_expression(), own, out);
}
collect_captured_binding_pattern(&prop.value, own, out);
}
if let Some(rest) = &op.rest {
collect_captured_binding_pattern(&rest.argument, own, out);
}
}
oxide_parser::BindingPattern::AssignmentPattern(ap) => {
collect_captured_expr(&ap.right, own, out);
collect_captured_binding_pattern(&ap.left, own, out);
}
}
}
/// 遍历绑定 pattern 的运行时求值表达式引用:计算键(`{[k]: a}` 的键)与内嵌
/// 默认值(`{a = x}` 的 x),供父层捕获判定(声明语句/for 头的模式与 catch/
/// 默认值路径同口径)。
pub(crate) fn collect_captured_binding_keys(
pattern: &oxide_parser::BindingPattern, own: &HashSet<String>, out: &mut HashSet<String>,
) {
match pattern {
oxide_parser::BindingPattern::BindingIdentifier(_) => {}
oxide_parser::BindingPattern::ArrayPattern(ap) => {
for p in ap.elements.iter().flatten() {
collect_captured_binding_keys(p, own, out);
}
if let Some(rest) = &ap.rest {
collect_captured_binding_keys(&rest.argument, own, out);
}
}
oxide_parser::BindingPattern::ObjectPattern(op) => {
for prop in &op.properties {
if prop.computed {
collect_captured_expr(prop.key.to_expression(), own, out);
}
collect_captured_binding_keys(&prop.value, own, out);
}
if let Some(rest) = &op.rest {
collect_captured_binding_keys(&rest.argument, own, out);
}
}
oxide_parser::BindingPattern::AssignmentPattern(ap) => {
// 内嵌默认值表达式引用外层绑定须建 cell(与 captured_binding_pattern
// 同口径);left 继续递归模式键。
collect_captured_expr(&ap.right, own, out);
collect_captured_binding_keys(&ap.left, own, out);
}
}
}
/// 以本函数 own 绑定集为过滤条件,判定表达式内嵌套函数捕获了哪些父绑定。与
/// `scanner.rs` 的 `collect_capture_names_expr` 相比,本函数以 own 为过滤条件做
/// 捕获最终判定,不接收显式 `ref_set`/`shadow`。
pub(crate) fn collect_captured_expr(expr: &Expression, own: &HashSet<String>, out: &mut HashSet<String>) {
match expr {
Expression::FunctionExpression(fe) => {
let body: &[Statement] = fe.body.as_ref().map(|b| &b.statements[..]).unwrap_or(&[]);
let mut inner = collect_fn_param_names(&fe.params);
inner.extend(collect_own_binding_names(&[], body));
collect_fn_default_captured(&fe.params, own, out);
let mut eng = CaptureEngine::new(own, inner, out);
collect_capture_names_shadowed(body, &mut eng);
}
Expression::ArrowFunctionExpression(ae) => {
let mut inner = collect_fn_param_names(&ae.params);
inner.extend(collect_own_binding_names(&[], &ae.body.statements));
collect_fn_default_captured(&ae.params, own, out);
let mut eng = CaptureEngine::new(own, inner, out);
collect_capture_names_shadowed(&ae.body.statements, &mut eng);
}
Expression::ClassExpression(class) => {
// 类表达式:构造器/方法体与字段表达式引用的父级绑定须建 cell。
let mut class_shadow = HashSet::new();
if let Some(id) = &class.id {
class_shadow.insert(id.name.as_str().to_string());
}
let mut eng = CaptureEngine::new(own, class_shadow, out);
collect_class_capture_names(&class.body, &mut eng);
}
Expression::CallExpression(ce) => {
collect_captured_expr(&ce.callee, own, out);
for a in &ce.arguments {
collect_captured_arg(a, own, out);
}
}
Expression::BinaryExpression(be) => {
collect_captured_expr(&be.left, own, out);
collect_captured_expr(&be.right, own, out);
}
Expression::UnaryExpression(ue) => collect_captured_expr(&ue.argument, own, out),
Expression::LogicalExpression(le) => {
collect_captured_expr(&le.left, own, out);
collect_captured_expr(&le.right, own, out);
}
Expression::ConditionalExpression(ce) => {
collect_captured_expr(&ce.test, own, out);
collect_captured_expr(&ce.consequent, own, out);
collect_captured_expr(&ce.alternate, own, out);
}
Expression::SequenceExpression(se) => {
for e in &se.expressions {
collect_captured_expr(e, own, out);
}
}
Expression::AssignmentExpression(ae) => {
// 只扫右侧:左侧赋值目标是本函数绑定,不引用嵌套函数;
// 若目标含嵌套函数表达式(如 `[f()] = ...`),由其自身递归处理。
collect_captured_expr(&ae.right, own, out);
}
Expression::UpdateExpression(_ue) => {} // 一元更新目标不引用嵌套函数,无需捕获
Expression::ArrayExpression(ae) => {
for e in &ae.elements {
if let Some(e) = e.as_expression() {
collect_captured_expr(e, own, out);
}
}
}
Expression::ObjectExpression(o) => {
for prop in &o.properties {
match prop {
oxide_parser::ObjectPropertyKind::ObjectProperty(p) => {
if p.computed {
collect_captured_expr(p.key.to_expression(), own, out);
}
collect_captured_expr(&p.value, own, out);
}
oxide_parser::ObjectPropertyKind::SpreadProperty(spread) => {
collect_captured_expr(&spread.argument, own, out);
}
}
}
}
Expression::NewExpression(ne) => {
collect_captured_expr(&ne.callee, own, out);
for a in &ne.arguments {
collect_captured_arg(a, own, out);
}
}
Expression::ComputedMemberExpression(m) => {
collect_captured_expr(&m.object, own, out);
collect_captured_expr(&m.expression, own, out);
}
Expression::StaticMemberExpression(m) => collect_captured_expr(&m.object, own, out),
Expression::PrivateFieldExpression(m) => collect_captured_expr(&m.object, own, out),
Expression::TemplateLiteral(tl) => {
for e in &tl.expressions {
collect_captured_expr(e, own, out);
}
}
Expression::TaggedTemplateExpression(tt) => {
collect_captured_expr(&tt.tag, own, out);
for e in &tt.quasi.expressions {
collect_captured_expr(e, own, out);
}
}
Expression::ParenthesizedExpression(p) => collect_captured_expr(&p.expression, own, out),
Expression::YieldExpression(ye) => {
if let Some(a) = &ye.argument {
collect_captured_expr(a, own, out);
}
}
Expression::AwaitExpression(ae) => collect_captured_expr(&ae.argument, own, out),
Expression::ChainExpression(c) => collect_captured_chain(&c.expression, own, out),
_ => {}
}
}
/// 遍历可选链元素,判定链上表达式对父绑定的捕获。
pub(crate) fn collect_captured_chain(
element: &oxide_parser::ChainElement, own: &HashSet<String>, out: &mut HashSet<String>,
) {
match element {
oxide_parser::ChainElement::StaticMemberExpression(m) => {
collect_captured_expr(&m.object, own, out);
}
oxide_parser::ChainElement::ComputedMemberExpression(m) => {
collect_captured_expr(&m.object, own, out);
collect_captured_expr(&m.expression, own, out);
}
oxide_parser::ChainElement::PrivateFieldExpression(m) => {
collect_captured_expr(&m.object, own, out);
}
oxide_parser::ChainElement::CallExpression(c) => {
collect_captured_expr(&c.callee, own, out);
for a in &c.arguments {
collect_captured_arg(a, own, out);
}
}
_ => {}
}
}
/// 遍历调用实参:静态实参与 spread 内部表达式都纳入捕获判定。
pub(crate) fn collect_captured_arg(arg: &oxide_parser::Argument, own: &HashSet<String>, out: &mut HashSet<String>) {
if let Some(e) = arg.as_expression() {
collect_captured_expr(e, own, out);
} else if let oxide_parser::Argument::SpreadElement(sp) = arg {
collect_captured_expr(&sp.argument, own, out);
}
}
-246
View File
@@ -1,246 +0,0 @@
//! 闭包捕获分析早退守卫:扫描语句树与附加表达式,判定是否存在嵌套函数/类节点,
//! 无嵌套时使捕获集收集(collect_captured_bindings,仅从嵌套函数/类节点产出名字)
//! 整体跳过。
//!
//! 关键约定:守卫臂集须与 `captured.rs` / `scanner.rs` 两收集器同步——新增 parser
//! 臂引入函数/类节点入口时三处同改;守卫漏任一入口臂即假阴,跳过捕获集收集导致
//! 嵌套函数 upvalue 捕获丢失。
use oxide_parser::{
Argument, AssignmentTarget, AssignmentTargetMaybeDefault, BindingPattern, ChainElement, Declaration,
ExportDefaultDeclarationKind, Expression, ForStatementLeft, SimpleAssignmentTarget, Statement,
};
/// 扫描语句树与附加表达式,判定是否存在嵌套函数/类节点(早退)。
///
/// 命中首个函数/类节点(函数声明/表达式、箭头函数、类声明/表达式)立即返回真,
/// 不分配任何集合、不克隆遮蔽集,单趟只读遍历显著轻于捕获集收集(每层嵌套函数
/// 克隆遮蔽集并再遍历)。
///
/// # 边界与前提
/// - `extra_exprs` 为参数默认值与类字段值表达式(位于函数体之外),与体同臂扫描。
/// - 臂集与 `captured.rs` / `scanner.rs` 两收集器逐臂对齐(含 pattern 计算键、
/// for 赋值头、catch 参数、export 包裹臂);新增 parser 臂引入函数/类节点入口
/// 时三处同改。
///
/// # 注意事项
/// - 守卫是跳过捕获集收集的必要条件:假阴(漏扫)丢 upvalue 捕获、读错 cell;
/// 假阳(多扫)仅使捕获集收集照跑,安全。
pub(crate) fn has_nested_function(stmts: &[Statement], extra_exprs: &[&Expression]) -> bool {
for stmt in stmts {
if scan_stmt(stmt) {
return true;
}
}
for expr in extra_exprs {
if scan_expr(expr) {
return true;
}
}
false
}
/// 扫描语句树:函数/类声明节点立即返回真,其余臂递归其表达式子节点,臂集与
/// 两收集器一致。
fn scan_stmt(stmt: &Statement) -> bool {
match stmt {
Statement::FunctionDeclaration(_) | Statement::ClassDeclaration(_) => true,
// export 包裹的声明:变量/函数/类声明体须下探。
Statement::ExportNamedDeclaration(exp) => match &exp.declaration {
Some(Declaration::VariableDeclaration(vd)) => scan_var_decl(vd),
Some(Declaration::FunctionDeclaration(_)) | Some(Declaration::ClassDeclaration(_)) => true,
_ => false,
},
Statement::ExportDefaultDeclaration(exp) => match &exp.declaration {
ExportDefaultDeclarationKind::FunctionDeclaration(_)
| ExportDefaultDeclarationKind::ClassDeclaration(_) => true,
other => other.as_expression().is_some_and(scan_expr),
},
Statement::ExpressionStatement(es) => scan_expr(&es.expression),
Statement::ReturnStatement(rs) => rs.argument.as_ref().is_some_and(scan_expr),
Statement::VariableDeclaration(vd) => scan_var_decl(vd),
Statement::IfStatement(is) => {
scan_expr(&is.test) || scan_stmt(&is.consequent) || is.alternate.as_ref().is_some_and(scan_stmt)
}
Statement::ForStatement(fs) => {
let init = fs.init.as_ref().is_some_and(|init| {
if let Some(e) = init.as_expression() {
scan_expr(e)
} else if let oxide_parser::ForStatementInit::VariableDeclaration(vd) = init {
scan_var_decl(vd)
} else {
false
}
});
init || fs.test.as_ref().is_some_and(scan_expr)
|| fs.update.as_ref().is_some_and(scan_expr)
|| scan_stmt(&fs.body)
}
Statement::WhileStatement(w) => scan_expr(&w.test) || scan_stmt(&w.body),
Statement::DoWhileStatement(d) => scan_stmt(&d.body) || scan_expr(&d.test),
Statement::ForInStatement(fi) => scan_expr(&fi.right) || scan_for_left(&fi.left) || scan_stmt(&fi.body),
Statement::ForOfStatement(fo) => scan_expr(&fo.right) || scan_for_left(&fo.left) || scan_stmt(&fo.body),
Statement::BlockStatement(b) => b.body.iter().any(scan_stmt),
Statement::TryStatement(ts) => {
ts.block.body.iter().any(scan_stmt)
|| ts.handler.as_ref().is_some_and(|h| {
// catch 参数 pattern 的内嵌默认值可含嵌套函数。
h.param.as_ref().is_some_and(|p| scan_binding_keys(&p.pattern)) || h.body.body.iter().any(scan_stmt)
})
|| ts.finalizer.as_ref().is_some_and(|f| f.body.iter().any(scan_stmt))
}
Statement::ThrowStatement(ts) => scan_expr(&ts.argument),
Statement::SwitchStatement(sw) => {
scan_expr(&sw.discriminant) || sw.cases.iter().any(|c| c.consequent.iter().any(scan_stmt))
}
Statement::LabeledStatement(ls) => scan_stmt(&ls.body),
Statement::WithStatement(ws) => scan_expr(&ws.object) || scan_stmt(&ws.body),
_ => false,
}
}
/// 变量声明:绑定 pattern 的计算键与内嵌默认值是运行时求值表达式,与初始化式
/// 同臂扫描。
fn scan_var_decl(vd: &oxide_parser::VariableDeclaration) -> bool {
vd.declarations
.iter()
.any(|d| scan_binding_keys(&d.id) || d.init.as_ref().is_some_and(scan_expr))
}
/// 遍历绑定 pattern 内运行时求值表达式:计算键(`{[k]: a}` 的键)与内嵌默认值
/// (`[x = expr]`),与 catch 参数 pattern 同形。
fn scan_binding_keys(pattern: &BindingPattern) -> bool {
match pattern {
BindingPattern::BindingIdentifier(_) => false,
BindingPattern::ArrayPattern(ap) => {
ap.elements.iter().flatten().any(scan_binding_keys)
|| ap.rest.as_ref().is_some_and(|rest| scan_binding_keys(&rest.argument))
}
BindingPattern::ObjectPattern(op) => {
op.properties
.iter()
.any(|prop| (prop.computed && scan_expr(prop.key.to_expression())) || scan_binding_keys(&prop.value))
|| op.rest.as_ref().is_some_and(|rest| scan_binding_keys(&rest.argument))
}
BindingPattern::AssignmentPattern(ap) => scan_expr(&ap.right) || scan_binding_keys(&ap.left),
}
}
/// for-in/for-of 头:声明头扫 pattern 键,赋值头扫解构目标元素(含默认值)。
fn scan_for_left(left: &ForStatementLeft) -> bool {
match left {
ForStatementLeft::VariableDeclaration(vd) => scan_var_decl(vd),
ForStatementLeft::ArrayAssignmentTarget(a) => scan_array_target(a),
ForStatementLeft::ObjectAssignmentTarget(o) => scan_object_target(o),
_ => false,
}
}
/// 赋值目标:成员目标扫对象/键,解构目标扫元素(含默认值)。
fn scan_assign_target(target: &AssignmentTarget) -> bool {
match target {
AssignmentTarget::StaticMemberExpression(m) => scan_expr(&m.object),
AssignmentTarget::ComputedMemberExpression(m) => scan_expr(&m.object) || scan_expr(&m.expression),
AssignmentTarget::ArrayAssignmentTarget(a) => scan_array_target(a),
AssignmentTarget::ObjectAssignmentTarget(o) => scan_object_target(o),
_ => false,
}
}
/// 数组赋值目标:元素(含默认值)与 rest 目标。
fn scan_array_target(a: &oxide_parser::ArrayAssignmentTarget) -> bool {
a.elements.iter().flatten().any(scan_maybe_default_target)
|| a.rest.as_ref().is_some_and(|rest| scan_assign_target(&rest.target))
}
/// 对象赋值目标:属性标识符默认值、属性名表达式、绑定目标与 rest。
fn scan_object_target(o: &oxide_parser::ObjectAssignmentTarget) -> bool {
o.properties.iter().any(|prop| match prop {
oxide_parser::AssignmentTargetProperty::AssignmentTargetPropertyIdentifier(id) => {
id.init.as_ref().is_some_and(scan_expr)
}
oxide_parser::AssignmentTargetProperty::AssignmentTargetPropertyProperty(p) => {
p.name.as_expression().is_some_and(scan_expr) || scan_maybe_default_target(&p.binding)
}
}) || o.rest.as_ref().is_some_and(|rest| scan_assign_target(&rest.target))
}
/// 解构赋值元素:带默认值的元素多一层(默认值表达式加绑定目标)。
fn scan_maybe_default_target(target: &AssignmentTargetMaybeDefault) -> bool {
match target {
AssignmentTargetMaybeDefault::AssignmentTargetWithDefault(d) => {
scan_expr(&d.init) || scan_assign_target(&d.binding)
}
AssignmentTargetMaybeDefault::StaticMemberExpression(m) => scan_expr(&m.object),
AssignmentTargetMaybeDefault::ComputedMemberExpression(m) => scan_expr(&m.object) || scan_expr(&m.expression),
AssignmentTargetMaybeDefault::ArrayAssignmentTarget(a) => scan_array_target(a),
AssignmentTargetMaybeDefault::ObjectAssignmentTarget(o) => scan_object_target(o),
_ => false,
}
}
/// 一元更新目标:成员目标扫对象/键。
fn scan_simple_target(target: &SimpleAssignmentTarget) -> bool {
match target {
SimpleAssignmentTarget::StaticMemberExpression(m) => scan_expr(&m.object),
SimpleAssignmentTarget::ComputedMemberExpression(m) => scan_expr(&m.object) || scan_expr(&m.expression),
_ => false,
}
}
/// 扫描表达式树:函数/类表达式节点立即返回真,其余臂递归,臂集与两收集器一致。
fn scan_expr(expr: &Expression) -> bool {
match expr {
Expression::FunctionExpression(_) | Expression::ArrowFunctionExpression(_) | Expression::ClassExpression(_) => {
true
}
Expression::CallExpression(ce) => scan_expr(&ce.callee) || ce.arguments.iter().any(scan_arg),
Expression::NewExpression(ne) => scan_expr(&ne.callee) || ne.arguments.iter().any(scan_arg),
Expression::BinaryExpression(be) => scan_expr(&be.left) || scan_expr(&be.right),
Expression::UnaryExpression(ue) => scan_expr(&ue.argument),
Expression::LogicalExpression(le) => scan_expr(&le.left) || scan_expr(&le.right),
Expression::ConditionalExpression(ce) => {
scan_expr(&ce.test) || scan_expr(&ce.consequent) || scan_expr(&ce.alternate)
}
Expression::SequenceExpression(se) => se.expressions.iter().any(scan_expr),
// 赋值目标侧也可含嵌套函数(解构目标默认值),左右同扫。
Expression::AssignmentExpression(ae) => scan_assign_target(&ae.left) || scan_expr(&ae.right),
Expression::UpdateExpression(ue) => scan_simple_target(&ue.argument),
Expression::ArrayExpression(ae) => ae.elements.iter().any(|e| e.as_expression().is_some_and(scan_expr)),
Expression::ObjectExpression(o) => o.properties.iter().any(|prop| match prop {
oxide_parser::ObjectPropertyKind::ObjectProperty(p) => {
(p.computed && scan_expr(p.key.to_expression())) || scan_expr(&p.value)
}
oxide_parser::ObjectPropertyKind::SpreadProperty(spread) => scan_expr(&spread.argument),
}),
Expression::ComputedMemberExpression(m) => scan_expr(&m.object) || scan_expr(&m.expression),
Expression::StaticMemberExpression(m) => scan_expr(&m.object),
Expression::PrivateFieldExpression(m) => scan_expr(&m.object),
Expression::TemplateLiteral(tl) => tl.expressions.iter().any(scan_expr),
Expression::TaggedTemplateExpression(tt) => scan_expr(&tt.tag) || tt.quasi.expressions.iter().any(scan_expr),
Expression::ParenthesizedExpression(p) => scan_expr(&p.expression),
Expression::YieldExpression(ye) => ye.argument.as_ref().is_some_and(scan_expr),
Expression::AwaitExpression(ae) => scan_expr(&ae.argument),
Expression::ChainExpression(c) => scan_chain(&c.expression),
_ => false,
}
}
/// 遍历可选链元素:成员访问、调用与实参。
fn scan_chain(element: &ChainElement) -> bool {
match element {
ChainElement::StaticMemberExpression(m) => scan_expr(&m.object),
ChainElement::ComputedMemberExpression(m) => scan_expr(&m.object) || scan_expr(&m.expression),
ChainElement::PrivateFieldExpression(m) => scan_expr(&m.object),
ChainElement::CallExpression(c) => scan_expr(&c.callee) || c.arguments.iter().any(scan_arg),
_ => false,
}
}
/// 调用实参:静态实参与 spread 内部表达式。
fn scan_arg(arg: &Argument) -> bool {
match arg {
Argument::SpreadElement(sp) => scan_expr(&sp.argument),
_ => arg.as_expression().is_some_and(scan_expr),
}
}
+3 -6
View File
@@ -5,22 +5,19 @@
//! 相同索引,保证父 MAKE_CELL 与子函数 upvalue 引用同一 cell),为 MAKE_CELL /
//! CELL_GET / CELL_SET 与子函数 upvalue cell_idx 提供统一依据。
//!
//! 五区严格单向分层(本文件 ← names ← scanner ← captured ← upvalues):
//! 四区严格单向分层(本文件 ← names ← scanner ← upvalues):
//! 跨区调用单向、无共享局部状态、无接收者状态。
mod captured;
mod guard;
mod names;
mod scanner;
mod upvalues;
use std::collections::HashSet;
pub(crate) use captured::collect_captured_bindings;
pub(crate) use guard::has_nested_function;
pub(crate) use names::collect_fn_scope_names;
pub(crate) use names::FnScopeNames;
pub(crate) use upvalues::collect_upvalue_names;
pub(crate) use upvalues::collect_captured_bindings;
pub(crate) use upvalues::collect_captures_and_upvalues;
/// 收集形参(含 rest)绑定的名字集,作为本函数作用域的遮蔽集。
pub(crate) fn collect_fn_param_names(params: &oxide_parser::FormalParameters) -> HashSet<String> {
+82 -44
View File
@@ -1,6 +1,7 @@
//! 闭包捕获分析,遮蔽感知引用收集:`CaptureEngine` 捆绑 ref_set(关注名集)×
//! shadow(遮蔽名集)× out(输出累加器)三集,遍历语句/表达式/赋值目标/类体
//! AST,嵌套函数/类/for 头/catch 参数逐层遮蔽,收集任意深度嵌套函数引用的名字。
//! 闭包捕获分析,遮蔽感知引用收集:`CaptureEngine` 捆绑双引用集(own ×
//! parent_names)× shadow(遮蔽名集)× 双输出累加器(captured_out ×
//! upvalue_out)× depth(嵌套深度),遍历语句/表达式/赋值目标/类体 AST,嵌套
//! 函数/类/for 头/catch 参数逐层遮蔽,按深度分区写两输出。
use std::collections::HashSet;
@@ -9,22 +10,60 @@ use oxide_parser::{ClassBody, ClassElement, Expression, Statement};
use super::names::collect_own_binding_names;
use super::{collect_fn_param_names, collect_for_left_decl_names};
/// 双引用集引擎:捆绑 ref_set(关注名集)、shadow(遮蔽名集)与 out(输出累加器)
/// 三集,本族十五个收集函数共享单一 `&mut CaptureEngine` 参数。作用域边界(嵌套
/// 函数/类/for 头/catch 参数)对 shadow 集做保存/恢复,逐层遮蔽外层绑定。
/// 双引用集引擎:捆绑 own(深度 ≥ 1 引用集)、parent_names(全深度引用集)、
/// sub_own(upvalue 显式排除集)、shadow(遮蔽名集)、depth(嵌套深度)与双输出
/// 累加器,本族十五个收集函数共享单一 `&mut CaptureEngine` 参数。作用域边界(嵌套
/// 函数/类/for 头/catch 参数)对 shadow 集做保存/恢复,逐层遮蔽外层绑定;函数/类
/// 边界对 depth 做增减,区分本函数体层与嵌套层。
pub(crate) struct CaptureEngine<'a> {
/// 关注名集:本次收集哪些名字(不可变)。
ref_set: &'a HashSet<String>,
/// 深度 ≥ 1 的引用集:本函数 own 绑定集(父层捕获判定)。
own: &'a HashSet<String>,
/// 全深度引用集:父捕获名 ∪ 父 upvalue 名(子层 upvalue 判定)。
parent_names: &'a HashSet<String>,
/// upvalue 判定的显式排除集:本函数 own 绑定集。
sub_own: &'a HashSet<String>,
/// 遮蔽名集:当前作用域内被遮蔽、须排除的名字;作用域边界保存/恢复。
shadow: HashSet<String>,
/// 输出累加器:本次收集到的名字。
out: &'a mut HashSet<String>,
/// 嵌套深度:0 = 本函数体层,≥ 1 = 嵌套函数/类内。
depth: u32,
/// 输出累加器:被嵌套函数捕获的名字(父层捕获判定)。
captured_out: &'a mut HashSet<String>,
/// 输出累加器:子函数引用父被捕获绑定的名字(子层 upvalue 判定)。
upvalue_out: &'a mut HashSet<String>,
}
impl<'a> CaptureEngine<'a> {
/// 构造引擎:`ref_set` 为关注名集,`shadow` 为初始遮蔽名集,`out` 为输出累加器。
pub(crate) fn new(ref_set: &'a HashSet<String>, shadow: HashSet<String>, out: &'a mut HashSet<String>) -> Self {
CaptureEngine { ref_set, shadow, out }
/// 构造引擎:`own` 为深度 ≥ 1 引用集,`parent_names` 为全深度引用集,
/// `sub_own` 为 upvalue 显式排除集,`captured_out` 与 `upvalue_out` 为双输出
/// 累加器。shadow 初始空,depth 初始 0。
pub(crate) fn new(
own: &'a HashSet<String>,
parent_names: &'a HashSet<String>,
sub_own: &'a HashSet<String>,
captured_out: &'a mut HashSet<String>,
upvalue_out: &'a mut HashSet<String>,
) -> Self {
CaptureEngine {
own,
parent_names,
sub_own,
shadow: HashSet::new(),
depth: 0,
captured_out,
upvalue_out,
}
}
/// 单一标识符检查点:按深度分区写两输出。
/// 深度 ≥ 1 且名字在 own 且不在 shadow → captured_out;
/// 名字在 parent_names 且不在 shadow 且不在 sub_own → upvalue_out。
fn check_identifier(&mut self, name: &str) {
if self.depth >= 1 && self.own.contains(name) && !self.shadow.contains(name) {
self.captured_out.insert(name.to_string());
}
if self.parent_names.contains(name) && !self.shadow.contains(name) && !self.sub_own.contains(name) {
self.upvalue_out.insert(name.to_string());
}
}
}
@@ -58,21 +97,25 @@ pub(crate) fn collect_capture_names_stmt(stmt: &Statement, eng: &mut CaptureEngi
Statement::FunctionDeclaration(fd) => {
let body: &[Statement] = fd.body.as_ref().map(|b| &b.statements[..]).unwrap_or(&[]);
collect_fn_default_names(&fd.params, eng);
// 函数形参与体内声明遮蔽外层绑定:影子集保存/恢复。
// 函数形参与体内声明遮蔽外层绑定:影子集保存/恢复,深度增一。
let saved = std::mem::take(&mut eng.shadow);
eng.shadow.extend(collect_fn_param_names(&fd.params));
eng.shadow.extend(collect_own_binding_names(&[], body));
eng.depth += 1;
collect_capture_names_shadowed(body, eng);
eng.depth -= 1;
eng.shadow = saved;
}
Statement::ClassDeclaration(cd) => {
// 类体(构造器/方法体、字段键与值、静态块)是嵌套作用域:
// 类名遮蔽外层绑定,方法形参与方法体局部进一步遮蔽。
// 类名遮蔽外层绑定,方法形参与方法体局部进一步遮蔽。深度增一。
let saved = std::mem::take(&mut eng.shadow);
if let Some(id) = &cd.id {
eng.shadow.insert(id.name.as_str().to_string());
}
eng.depth += 1;
collect_class_capture_names(&cd.body, eng);
eng.depth -= 1;
eng.shadow = saved;
}
Statement::IfStatement(is) => {
@@ -181,7 +224,9 @@ pub(crate) fn collect_capture_names_stmt(stmt: &Statement, eng: &mut CaptureEngi
let saved = std::mem::take(&mut eng.shadow);
eng.shadow.extend(collect_fn_param_names(&fd.params));
eng.shadow.extend(collect_own_binding_names(&[], body));
eng.depth += 1;
collect_capture_names_shadowed(body, eng);
eng.depth -= 1;
eng.shadow = saved;
}
oxide_parser::Declaration::ClassDeclaration(cd) => {
@@ -189,7 +234,9 @@ pub(crate) fn collect_capture_names_stmt(stmt: &Statement, eng: &mut CaptureEngi
if let Some(id) = &cd.id {
eng.shadow.insert(id.name.as_str().to_string());
}
eng.depth += 1;
collect_class_capture_names(&cd.body, eng);
eng.depth -= 1;
eng.shadow = saved;
}
_ => {}
@@ -203,7 +250,9 @@ pub(crate) fn collect_capture_names_stmt(stmt: &Statement, eng: &mut CaptureEngi
let saved = std::mem::take(&mut eng.shadow);
eng.shadow.extend(collect_fn_param_names(&fd.params));
eng.shadow.extend(collect_own_binding_names(&[], body));
eng.depth += 1;
collect_capture_names_shadowed(body, eng);
eng.depth -= 1;
eng.shadow = saved;
}
oxide_parser::ExportDefaultDeclarationKind::ClassDeclaration(cd) => {
@@ -211,7 +260,9 @@ pub(crate) fn collect_capture_names_stmt(stmt: &Statement, eng: &mut CaptureEngi
if let Some(id) = &cd.id {
eng.shadow.insert(id.name.as_str().to_string());
}
eng.depth += 1;
collect_class_capture_names(&cd.body, eng);
eng.depth -= 1;
eng.shadow = saved;
}
other => {
@@ -367,10 +418,7 @@ pub(crate) fn collect_capture_names_binding_keys(pattern: &oxide_parser::Binding
pub(crate) fn collect_capture_names_assign_target(target: &oxide_parser::AssignmentTarget, eng: &mut CaptureEngine) {
match target {
oxide_parser::AssignmentTarget::AssignmentTargetIdentifier(ati) => {
let name = ati.name.as_str();
if eng.ref_set.contains(name) && !eng.shadow.contains(name) {
eng.out.insert(ati.name.to_string());
}
eng.check_identifier(ati.name.as_str());
}
oxide_parser::AssignmentTarget::StaticMemberExpression(m) => {
collect_capture_names_expr(&m.object, eng);
@@ -408,9 +456,7 @@ fn collect_capture_names_array_target(a: &oxide_parser::ArrayAssignmentTarget, e
fn collect_capture_names_object_target(o: &oxide_parser::ObjectAssignmentTarget, eng: &mut CaptureEngine) {
for prop in &o.properties {
if let oxide_parser::AssignmentTargetProperty::AssignmentTargetPropertyIdentifier(id) = prop {
if eng.ref_set.contains(id.binding.name.as_str()) && !eng.shadow.contains(id.binding.name.as_str()) {
eng.out.insert(id.binding.name.to_string());
}
eng.check_identifier(id.binding.name.as_str());
if let Some(init) = &id.init {
collect_capture_names_expr(init, eng);
}
@@ -431,10 +477,7 @@ fn collect_capture_names_object_target(o: &oxide_parser::ObjectAssignmentTarget,
pub(crate) fn collect_capture_names_for_left(left: &oxide_parser::ForStatementLeft, eng: &mut CaptureEngine) {
match left {
oxide_parser::ForStatementLeft::AssignmentTargetIdentifier(id) => {
let name = id.name.as_str();
if eng.ref_set.contains(name) && !eng.shadow.contains(name) {
eng.out.insert(name.to_string());
}
eng.check_identifier(id.name.as_str());
}
oxide_parser::ForStatementLeft::ArrayAssignmentTarget(a) => {
collect_capture_names_array_target(a, eng);
@@ -465,10 +508,7 @@ pub(crate) fn collect_capture_names_maybe_default_target(
collect_capture_names_assign_target(&d.binding, eng);
}
MaybeDefault::AssignmentTargetIdentifier(ati) => {
let name = ati.name.as_str();
if eng.ref_set.contains(name) && !eng.shadow.contains(name) {
eng.out.insert(ati.name.to_string());
}
eng.check_identifier(ati.name.as_str());
}
MaybeDefault::StaticMemberExpression(m) => {
collect_capture_names_expr(&m.object, eng);
@@ -485,10 +525,7 @@ pub(crate) fn collect_capture_names_maybe_default_target(
MaybeDefault::ObjectAssignmentTarget(o) => {
for prop in &o.properties {
if let oxide_parser::AssignmentTargetProperty::AssignmentTargetPropertyIdentifier(id) = prop {
if eng.ref_set.contains(id.binding.name.as_str()) && !eng.shadow.contains(id.binding.name.as_str())
{
eng.out.insert(id.binding.name.to_string());
}
eng.check_identifier(id.binding.name.as_str());
if let Some(init) = &id.init {
collect_capture_names_expr(init, eng);
}
@@ -515,10 +552,7 @@ pub(crate) fn collect_capture_names_simple_target(
) {
match target {
oxide_parser::SimpleAssignmentTarget::AssignmentTargetIdentifier(ati) => {
let name = ati.name.as_str();
if eng.ref_set.contains(name) && !eng.shadow.contains(name) {
eng.out.insert(ati.name.to_string());
}
eng.check_identifier(ati.name.as_str());
}
oxide_parser::SimpleAssignmentTarget::StaticMemberExpression(m) => {
collect_capture_names_expr(&m.object, eng);
@@ -555,10 +589,7 @@ pub(crate) fn collect_fn_default_names(params: &oxide_parser::FormalParameters,
pub(crate) fn collect_capture_names_expr(expr: &Expression, eng: &mut CaptureEngine) {
match expr {
Expression::Identifier(id) => {
let name = id.name.as_str();
if eng.ref_set.contains(name) && !eng.shadow.contains(name) {
eng.out.insert(id.name.to_string());
}
eng.check_identifier(id.name.as_str());
}
Expression::AssignmentExpression(ae) => {
// 赋值目标里的引用也须捕获:标识符目标写名,成员/解构目标扫描其对象/元素。
@@ -571,28 +602,35 @@ pub(crate) fn collect_capture_names_expr(expr: &Expression, eng: &mut CaptureEng
Expression::FunctionExpression(fe) => {
let body: &[Statement] = fe.body.as_ref().map(|b| &b.statements[..]).unwrap_or(&[]);
collect_fn_default_names(&fe.params, eng);
// 函数形参与体内声明遮蔽外层绑定:影子集保存/恢复。
// 函数形参与体内声明遮蔽外层绑定:影子集保存/恢复,深度增一。
let saved = std::mem::take(&mut eng.shadow);
eng.shadow.extend(collect_fn_param_names(&fe.params));
eng.shadow.extend(collect_own_binding_names(&[], body));
eng.depth += 1;
collect_capture_names_shadowed(body, eng);
eng.depth -= 1;
eng.shadow = saved;
}
Expression::ArrowFunctionExpression(ae) => {
collect_fn_default_names(&ae.params, eng);
// 函数形参与体内声明遮蔽外层绑定:影子集保存/恢复,深度增一。
let saved = std::mem::take(&mut eng.shadow);
eng.shadow.extend(collect_fn_param_names(&ae.params));
eng.shadow.extend(collect_own_binding_names(&[], &ae.body.statements));
eng.depth += 1;
collect_capture_names_shadowed(&ae.body.statements, eng);
eng.depth -= 1;
eng.shadow = saved;
}
Expression::ClassExpression(class) => {
// 类表达式:方法/构造器体与字段表达式是嵌套作用域,引用须捕获。
// 类表达式:方法/构造器体与字段表达式是嵌套作用域,引用须捕获。深度增一。
let saved = std::mem::take(&mut eng.shadow);
if let Some(id) = &class.id {
eng.shadow.insert(id.name.as_str().to_string());
}
eng.depth += 1;
collect_class_capture_names(&class.body, eng);
eng.depth -= 1;
eng.shadow = saved;
}
Expression::BinaryExpression(be) => {
+51 -22
View File
@@ -1,39 +1,55 @@
//! 闭包捕获分析,子函数 upvalue 分析:子函数体对父被捕获绑定的引用
//! → Vec<UpvalueCapture>(排序对齐 cell_idx,enclosing_reg 留 0 待
//! assemble_ir 填充)。
//! 闭包捕获分析,单入口收集:对同一 AST(body_stmts + extra_exprs)单趟产出
//! 两个输出(captured_bindings 的 BTreeMap 与 upvalue_captures 的 Vec)。
//! 顶层两个薄包装 `collect_captured_bindings` / `collect_upvalue_names` 签名不变,
//! 调用点不动。
use std::collections::{BTreeMap, HashSet};
use oxide_bytecode::module::UpvalueCapture;
use oxide_parser::Statement;
use oxide_parser::{Expression, Statement};
use super::scanner::{collect_capture_names_expr, collect_capture_names_shadowed, CaptureEngine};
/// 分析子函数 body:引用父级被捕获绑定的名字 → upvalue_captures。
/// 名字若在父 `captured_bindings`(父 own cell)则 `cell_idx` 索引定义方表;
/// 若在父 `upvalue_captures`(父自身从更外层捕获)则链式标记 `parent_uv_idx`,
/// 运行时从父闭包 upvalues 取 cell。enclosing_reg 由父 emit 完成后填充。
pub(crate) fn collect_upvalue_names(
body_stmts: &[Statement], extra_exprs: &[&oxide_parser::Expression], parent_captured: &BTreeMap<String, u8>,
parent_upvalues: &[UpvalueCapture], sub_own: &HashSet<String>,
) -> Vec<UpvalueCapture> {
/// 单入口:对同一 AST 单趟产出两个输出(captured_bindings 的 BTreeMap 与
/// upvalue_captures 的 Vec)。`own` 为父层捕获判定引用集(深度 ≥ 1 生效),
/// `parent_captured` 与 `parent_upvalues` 为父层两映射(构建全深度引用集),
/// `sub_own` 为 upvalue 判定的显式排除集。
pub(crate) fn collect_captures_and_upvalues(
body_stmts: &[Statement],
extra_exprs: &[&Expression],
own: &HashSet<String>,
parent_captured: &BTreeMap<String, u8>,
parent_upvalues: &[UpvalueCapture],
sub_own: &HashSet<String>,
) -> (BTreeMap<String, u8>, Vec<UpvalueCapture>) {
// 构建全深度引用集:父捕获名 ∪ 父 upvalue 名。
let mut parent_names: HashSet<String> = parent_captured.keys().cloned().collect();
for u in parent_upvalues {
parent_names.insert(u.name.clone());
}
let mut names = HashSet::new();
let mut eng = CaptureEngine::new(&parent_names, sub_own.clone(), &mut names);
// 双输出累加器。
let mut captured_out: HashSet<String> = HashSet::new();
let mut upvalue_out: HashSet<String> = HashSet::new();
// 构造引擎并扫描。
let mut eng = CaptureEngine::new(own, &parent_names, sub_own, &mut captured_out, &mut upvalue_out);
collect_capture_names_shadowed(body_stmts, &mut eng);
// 参数默认值表达式(不在 body_stmts)里的嵌套函数引用也会捕获父变量。
for expr in extra_exprs {
collect_capture_names_expr(expr, &mut eng);
}
// HashSet 迭代序带随机种子(进程级非确定),必须排序使 upvalue_captures 的顺序与
// 父 captured_bindings 的 cell_idx(BTreeMap 名字序)对齐——否则 LOAD_UPVALUE 的
// a 槽 uv_idx 编码与 cell_idx 错位,读错 upvalue。
let mut names: Vec<String> = names.into_iter().collect();
names.sort();
names
// 输出整形:captured_out 排序后按枚举序分配 cell_idx 成 BTreeMap。
let mut captured_sorted: Vec<String> = captured_out.into_iter().collect();
captured_sorted.sort();
let captured_map: BTreeMap<String, u8> =
captured_sorted.into_iter().enumerate().map(|(i, n)| (n, i as u8)).collect();
// 输出整形:upvalue_out 排序后逐名取 cell_idx(父捕获映射)与 parent_uv_idx
// (父 upvalue 向量位置)成 Vec<UpvalueCapture>。
let mut upvalue_sorted: Vec<String> = upvalue_out.into_iter().collect();
upvalue_sorted.sort();
let upvalue_vec: Vec<UpvalueCapture> = upvalue_sorted
.into_iter()
.map(|name| {
let parent_uv_idx = parent_upvalues.iter().position(|u| u.name == name).map(|i| i as u8);
@@ -45,5 +61,18 @@ pub(crate) fn collect_upvalue_names(
parent_uv_idx,
}
})
.collect()
.collect();
(captured_map, upvalue_vec)
}
/// 薄包装:父层捕获判定。`collect_captured_bindings(stmts, extra, own)` =
/// 入口(own, 空父映射).0。签名不变,调用点不动。
pub(crate) fn collect_captured_bindings(
stmts: &[Statement], extra_exprs: &[&Expression], own: &HashSet<String>,
) -> BTreeMap<String, u8> {
let empty_map: BTreeMap<String, u8> = BTreeMap::new();
let empty_vec: Vec<UpvalueCapture> = Vec::new();
let empty_set: HashSet<String> = HashSet::new();
collect_captures_and_upvalues(stmts, extra_exprs, own, &empty_map, &empty_vec, &empty_set).0
}
+34 -34
View File
@@ -14,8 +14,7 @@ use oxide_ir::IRFunction;
use oxide_parser::{Expression, Statement, VariableDeclarationKind};
use crate::capture::{
collect_binding_pattern_names, collect_captured_bindings, collect_fn_scope_names, collect_upvalue_names,
has_nested_function, FnScopeNames,
collect_binding_pattern_names, collect_captures_and_upvalues, collect_fn_scope_names, FnScopeNames,
};
use crate::compile_ctx::{CompileCtx, FieldBuffer};
use crate::symbol_table::{Binding, ScopeKind};
@@ -703,13 +702,8 @@ impl Emitter {
ParamSpec::Rest { .. } => {}
}
}
// 早退守卫:体与附加表达式无嵌套函数/类节点时,捕获集
// (collect_captured_bindings,仅从嵌套函数/类节点产出名字)必为空,跳过该
// 趟;own_bindings 是 upvalue 分析的遮蔽集、upvalue 捕获是本体对父的捕获,
// 二者独立于嵌套函数,不得跳过。
let mut capture_exprs: Vec<&oxide_parser::Expression> = param_defaults.clone();
capture_exprs.extend_from_slice(extra_capture_exprs);
let has_nested = has_nested_function(body_stmts, &capture_exprs);
ctx.own_bindings = scope_names.own_binding_names.clone();
for spec in param_specs {
if let ParamSpec::Pattern { pattern, .. } = spec {
@@ -766,27 +760,25 @@ impl Emitter {
}
}
if has_nested {
ctx.set_captured_bindings(collect_captured_bindings(body_stmts, &capture_exprs, &ctx.own_bindings));
}
// 自由变量分析:收集 upvalue 捕获(类方法也是普通函数,可捕获外层变量)。
if matches!(
// 单入口:对同一 AST 单趟产出两个输出(captured_bindings 与 upvalue_captures)。
let is_closure_context = matches!(
body_context,
FunctionBodyContext::Ordinary | FunctionBodyContext::Arrow | FunctionBodyContext::ClassElement
) {
// 只有创建点父作用域链内可解析的父捕获名才可能成为子函数 upvalue:
// 捕获集是函数级名字并集,块级 let/const 在块退出后 cell 仍存留但名字
// 已不可解析,块外嵌套函数按名命中会错误读取已失效的 cell。父自身
// upvalue 代表的祖父绑定在父函数体内恒可见,不参与过滤。
// C 风格 for 头 let/const 名在 init 内尚未 declare,但同头声明会为其
// 建 cell,前向捕获须按父捕获集保留(见 `pending_for_head_names`)。
// 索引按父可见绑定实例取(块级遮蔽绑定持追加索引);词法循环头名
// (for-in/for-of 头绑定在右值区编译时未进符号表,按名回查会误命中
// 外层同名绑定)与 for 头前向名无条件取捕获映射值(ForHeadEnv 覆盖
// 索引或名字排序索引);绑定未分配索引的其余名(命名空间导入等)
// 回退映射值。顶层 tier 名(顶层 var/函数)已在捕获集剔除阶段出集,
// 不在此列。
let visible_parent_captured: BTreeMap<String, u8> = parent_ctx
);
// 只有创建点父作用域链内可解析的父捕获名才可能成为子函数 upvalue:
// 捕获集是函数级名字并集,块级 let/const 在块退出后 cell 仍存留但名字
// 已不可解析,块外嵌套函数按名命中会错误读取已失效的 cell。父自身
// upvalue 代表的祖父绑定在父函数体内恒可见,不参与过滤。
// C 风格 for 头 let/const 名在 init 内尚未 declare,但同头声明会为其
// 建 cell,前向捕获须按父捕获集保留(见 `pending_for_head_names`)。
// 索引按父可见绑定实例取(块级遮蔽绑定持追加索引);词法循环头名
// (for-in/for-of 头绑定在右值区编译时未进符号表,按名回查会误命中
// 外层同名绑定)与 for 头前向名无条件取捕获映射值(ForHeadEnv 覆盖
// 索引或名字排序索引);绑定未分配索引的其余名(命名空间导入等)
// 回退映射值。顶层 tier 名(顶层 var/函数)已在捕获集剔除阶段出集,
// 不在此列。
let visible_parent_captured: BTreeMap<String, u8> = if is_closure_context {
parent_ctx
.captured_bindings
.iter()
.filter(|(n, _)| {
@@ -830,14 +822,22 @@ impl Emitter {
};
(n.clone(), idx)
})
.collect();
ctx.current_upvalue_captures = collect_upvalue_names(
body_stmts,
&capture_exprs,
&visible_parent_captured,
&parent_ctx.current_upvalue_captures,
&ctx.own_bindings,
);
.collect()
} else {
BTreeMap::new()
};
let (captured_map, upvalue_vec) = collect_captures_and_upvalues(
body_stmts,
&capture_exprs,
&ctx.own_bindings,
&visible_parent_captured,
&parent_ctx.current_upvalue_captures,
&ctx.own_bindings,
);
ctx.set_captured_bindings(captured_map);
// 自由变量分析:收集 upvalue 捕获(类方法也是普通函数,可捕获外层变量)。
if is_closure_context {
ctx.current_upvalue_captures = upvalue_vec;
// 捕获 const 信息快照:父作用域符号表此时完整(预声明已完成),
// 直接查绑定 is_const(不依赖初始化状态,TDZ 中 const 也须拦截)。
ctx.upvalue_const_flags = ctx