mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
perf: 捕获判定与upvalue收集合并单入口
This commit is contained in:
Generated
+20
-20
@@ -1160,7 +1160,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_builtins"
|
||||
version = "0.16.7"
|
||||
version = "0.16.8"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"fast-float",
|
||||
@@ -1185,7 +1185,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_bytecode"
|
||||
version = "0.16.7"
|
||||
version = "0.16.8"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"oxide_log",
|
||||
@@ -1193,7 +1193,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_cfg"
|
||||
version = "0.16.7"
|
||||
version = "0.16.8"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_emit",
|
||||
@@ -1204,7 +1204,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_cli"
|
||||
version = "0.16.7"
|
||||
version = "0.16.8"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"bumpalo",
|
||||
@@ -1228,7 +1228,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_code_cache"
|
||||
version = "0.16.7"
|
||||
version = "0.16.8"
|
||||
dependencies = [
|
||||
"lru",
|
||||
"oxide_bytecode",
|
||||
@@ -1237,7 +1237,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_compiler"
|
||||
version = "0.16.7"
|
||||
version = "0.16.8"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1257,7 +1257,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_dce"
|
||||
version = "0.16.7"
|
||||
version = "0.16.8"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1271,7 +1271,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_emit"
|
||||
version = "0.16.7"
|
||||
version = "0.16.8"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"oxc_allocator",
|
||||
@@ -1286,7 +1286,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_engine"
|
||||
version = "0.16.7"
|
||||
version = "0.16.8"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_compiler",
|
||||
@@ -1298,7 +1298,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_ir"
|
||||
version = "0.16.7"
|
||||
version = "0.16.8"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_log",
|
||||
@@ -1307,7 +1307,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_kernel"
|
||||
version = "0.16.7"
|
||||
version = "0.16.8"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"dashmap",
|
||||
@@ -1321,7 +1321,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_liveness"
|
||||
version = "0.16.7"
|
||||
version = "0.16.8"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1333,7 +1333,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_log"
|
||||
version = "0.16.7"
|
||||
version = "0.16.8"
|
||||
dependencies = [
|
||||
"tracing",
|
||||
"tracing-appender",
|
||||
@@ -1342,11 +1342,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_net"
|
||||
version = "0.16.7"
|
||||
version = "0.16.8"
|
||||
|
||||
[[package]]
|
||||
name = "oxide_parser"
|
||||
version = "0.16.7"
|
||||
version = "0.16.8"
|
||||
dependencies = [
|
||||
"oxc_allocator",
|
||||
"oxc_ast",
|
||||
@@ -1361,7 +1361,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_regalloc"
|
||||
version = "0.16.7"
|
||||
version = "0.16.8"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1377,7 +1377,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_runtime_api"
|
||||
version = "0.16.7"
|
||||
version = "0.16.8"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
@@ -1390,7 +1390,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_test262"
|
||||
version = "0.16.7"
|
||||
version = "0.16.8"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_compiler",
|
||||
@@ -1410,7 +1410,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_types"
|
||||
version = "0.16.7"
|
||||
version = "0.16.8"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"dashmap",
|
||||
@@ -1423,7 +1423,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_vm"
|
||||
version = "0.16.7"
|
||||
version = "0.16.8"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"chrono",
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.16.7"
|
||||
version = "0.16.8"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
rust-version = "1.80"
|
||||
|
||||
@@ -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 ¶ms.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(¶m.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);
|
||||
}
|
||||
}
|
||||
@@ -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),
|
||||
}
|
||||
}
|
||||
@@ -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> {
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user