Files
OxideJS-New/crates/oxide_emit/src/capture/names.rs
T

438 lines
20 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! 闭包捕获分析,own/var/顶层声明名收集:本函数 own_bindings 名集
//! (参数名 + 变量/函数/import/export 声明,含嵌套块)、var 提升入口
//! 名集、顶层函数声明名集(无序集 + 声明序列表)。
use std::collections::HashSet;
use oxide_parser::{Statement, VariableDeclarationKind};
use super::{collect_binding_pattern_names, collect_for_left_decl_names};
/// 收集语句树中全部 `var` 声明名(var 提升到函数/程序作用域,递归进嵌套块)。
/// 供函数/程序入口批量 MAKE_CELL(undefined) 使用(var 入口实例化语义)。
pub(crate) fn collect_var_binding_names(stmts: &[Statement]) -> HashSet<String> {
let mut names = HashSet::new();
collect_var_names_stmt(stmts, &mut names);
names
}
/// 递归遍历语句树收集 `var` 声明名(函数/程序级提升目标),含嵌套块与控制流各分支。
pub(crate) fn collect_var_names_stmt(stmts: &[Statement], out: &mut HashSet<String>) {
for stmt in stmts {
match stmt {
Statement::VariableDeclaration(vd) => {
if matches!(vd.kind, VariableDeclarationKind::Var) {
for d in &vd.declarations {
collect_binding_pattern_names(&d.id, out);
}
}
}
Statement::BlockStatement(b) => collect_var_names_stmt(&b.body, out),
Statement::IfStatement(is) => {
collect_var_names_stmt(std::slice::from_ref(&is.consequent), out);
if let Some(alt) = &is.alternate {
collect_var_names_stmt(std::slice::from_ref(alt), out);
}
}
Statement::WhileStatement(w) => collect_var_names_stmt(std::slice::from_ref(&w.body), out),
Statement::DoWhileStatement(d) => collect_var_names_stmt(std::slice::from_ref(&d.body), out),
Statement::ForStatement(f) => {
if let Some(oxide_parser::ForStatementInit::VariableDeclaration(vd)) = &f.init {
if matches!(vd.kind, VariableDeclarationKind::Var) {
for d in &vd.declarations {
collect_binding_pattern_names(&d.id, out);
}
}
}
collect_var_names_stmt(std::slice::from_ref(&f.body), out);
}
Statement::ForInStatement(fi) => {
if let oxide_parser::ForStatementLeft::VariableDeclaration(vd) = &fi.left {
// 仅 var 头名提升到函数作用域,let/const 头名是迭代级绑定。
if matches!(vd.kind, VariableDeclarationKind::Var) {
collect_for_left_decl_names(&fi.left, out);
}
}
collect_var_names_stmt(std::slice::from_ref(&fi.body), out);
}
Statement::ForOfStatement(fo) => {
if let oxide_parser::ForStatementLeft::VariableDeclaration(vd) = &fo.left {
// 仅 var 头名提升到函数作用域,let/const 头名是迭代级绑定。
if matches!(vd.kind, VariableDeclarationKind::Var) {
collect_for_left_decl_names(&fo.left, out);
}
}
collect_var_names_stmt(std::slice::from_ref(&fo.body), out);
}
Statement::SwitchStatement(sw) => {
for case in &sw.cases {
collect_var_names_stmt(&case.consequent, out);
}
}
Statement::TryStatement(ts) => {
collect_var_names_stmt(&ts.block.body, out);
if let Some(h) = &ts.handler {
collect_var_names_stmt(&h.body.body, out);
}
if let Some(f) = &ts.finalizer {
collect_var_names_stmt(&f.body, out);
}
}
Statement::LabeledStatement(ls) => collect_var_names_stmt(std::slice::from_ref(&ls.body), out),
Statement::WithStatement(ws) => collect_var_names_stmt(std::slice::from_ref(&ws.body), out),
Statement::ExportNamedDeclaration(exp) => {
if let Some(oxide_parser::Declaration::VariableDeclaration(vd)) = &exp.declaration {
if matches!(vd.kind, VariableDeclarationKind::Var) {
for d in &vd.declarations {
collect_binding_pattern_names(&d.id, out);
}
}
}
}
_ => {}
}
}
}
/// 收集语句列表**直接子级**函数声明的绑定名(顶层函数声明是全局 var 绑定,
/// 裸读/裸写与 var 名同路由全局对象属性)。不递归进块:块内函数声明是块
/// 作用域,不参与全局对象同步;`export default function` 是 lexical 绑定,不纳。
pub(crate) fn collect_top_level_function_names(stmts: &[Statement]) -> HashSet<String> {
let mut names = HashSet::new();
for stmt in stmts {
if let Statement::FunctionDeclaration(fd) = stmt {
if let Some(id) = &fd.id {
names.insert(id.name.to_string());
}
}
}
names
}
/// 同 [`collect_top_level_function_names`] 的收集面,但按**声明序**返回 Vec
/// (供 GlobalDeclarationInstantiation(脚本顶层声明实例化)检查阶段逆序遍历逐名
/// 去重,规范"逆序首见 = 源序最后声明";重名只查一次,取源序最后一次声明)。
pub(crate) fn collect_top_level_function_names_ordered(stmts: &[Statement]) -> Vec<String> {
let mut names = Vec::new();
for stmt in stmts {
if let Statement::FunctionDeclaration(fd) = stmt {
if let Some(id) = &fd.id {
names.push(id.name.to_string());
}
}
}
names
}
/// 收集语句列表**直接子级**词法声明名(let/const,含解构 pattern 叶):
/// 入口 TDZ 占位 cell 名集(被捕获的词法绑定在入口未初始化)。
///
/// 遍历面与 `predeclare_lexical_declarations` 一致——只走直接子级,不递归块/
/// if/for/switch case/try 区(块级名不提升到函数/程序作用域,不建入口
/// cell);for 头声明是循环作用域绑定,不纳;var 声明不纳(var 入口实例化
/// 独立覆盖);import 绑定由模块导入初始化的发射点建 cell,不纳。
pub(crate) fn collect_direct_lexical_names(stmts: &[Statement]) -> HashSet<String> {
let mut names = HashSet::new();
for stmt in stmts {
match stmt {
Statement::VariableDeclaration(decl) => {
if matches!(decl.kind, VariableDeclarationKind::Var) {
continue;
}
for d in &decl.declarations {
collect_binding_pattern_names(&d.id, &mut names);
}
}
Statement::ClassDeclaration(cd) => {
if let Some(id) = &cd.id {
names.insert(id.name.to_string());
}
}
Statement::ExportNamedDeclaration(exp) => {
if let Some(decl) = &exp.declaration {
match decl {
oxide_parser::Declaration::VariableDeclaration(vd) => {
if matches!(vd.kind, VariableDeclarationKind::Var) {
continue;
}
for d in &vd.declarations {
collect_binding_pattern_names(&d.id, &mut names);
}
}
oxide_parser::Declaration::ClassDeclaration(cd) => {
if let Some(id) = &cd.id {
names.insert(id.name.to_string());
}
}
_ => {}
}
}
}
Statement::ExportDefaultDeclaration(exp) => {
if let oxide_parser::ExportDefaultDeclarationKind::ClassDeclaration(cd) = &exp.declaration {
if let Some(id) = &cd.id {
names.insert(id.name.to_string());
}
}
}
_ => {}
}
}
names
}
/// 收集块级声明名(块内 let/const/class、catch 参数、for 头 let/const):
/// 这些名字是块作用域绑定,遮蔽同名顶层 tier 名时,tier 名须保留在捕获集,
/// 块级绑定才能追加新索引供闭包捕获。顶层直接子级 let/const/class 是顶层
/// 词法绑定,不纳;var 声明不纳(var 是函数/全局作用域)。
pub(crate) fn collect_block_level_decl_names(stmts: &[Statement]) -> HashSet<String> {
let mut names = HashSet::new();
collect_block_level_names_stmt(stmts, &mut names, true);
names
}
/// 递归遍历语句树收集块级声明名。`top` 标记当前层是否为顶层(顶层直接子级
/// let/const/class 是顶层词法绑定,非块级)。
fn collect_block_level_names_stmt(stmts: &[Statement], out: &mut HashSet<String>, top: bool) {
for stmt in stmts {
match stmt {
Statement::VariableDeclaration(vd) => {
if matches!(vd.kind, VariableDeclarationKind::Var) || top {
continue;
}
for d in &vd.declarations {
collect_binding_pattern_names(&d.id, out);
}
}
Statement::ClassDeclaration(cd) => {
if !top {
if let Some(id) = &cd.id {
out.insert(id.name.to_string());
}
}
}
Statement::BlockStatement(b) => collect_block_level_names_stmt(&b.body, out, false),
Statement::IfStatement(is) => {
collect_block_level_names_stmt(std::slice::from_ref(&is.consequent), out, false);
if let Some(alt) = &is.alternate {
collect_block_level_names_stmt(std::slice::from_ref(alt), out, false);
}
}
Statement::WhileStatement(w) => collect_block_level_names_stmt(std::slice::from_ref(&w.body), out, false),
Statement::DoWhileStatement(d) => collect_block_level_names_stmt(std::slice::from_ref(&d.body), out, false),
Statement::ForStatement(f) => {
if let Some(oxide_parser::ForStatementInit::VariableDeclaration(vd)) = &f.init {
if !matches!(vd.kind, VariableDeclarationKind::Var) {
for d in &vd.declarations {
collect_binding_pattern_names(&d.id, out);
}
}
}
collect_block_level_names_stmt(std::slice::from_ref(&f.body), out, false);
}
Statement::ForInStatement(fi) => {
if let oxide_parser::ForStatementLeft::VariableDeclaration(vd) = &fi.left {
if !matches!(vd.kind, VariableDeclarationKind::Var) {
collect_for_left_decl_names(&fi.left, out);
}
}
collect_block_level_names_stmt(std::slice::from_ref(&fi.body), out, false);
}
Statement::ForOfStatement(fo) => {
if let oxide_parser::ForStatementLeft::VariableDeclaration(vd) = &fo.left {
if !matches!(vd.kind, VariableDeclarationKind::Var) {
collect_for_left_decl_names(&fo.left, out);
}
}
collect_block_level_names_stmt(std::slice::from_ref(&fo.body), out, false);
}
Statement::SwitchStatement(sw) => {
for case in &sw.cases {
collect_block_level_names_stmt(&case.consequent, out, false);
}
}
Statement::TryStatement(ts) => {
collect_block_level_names_stmt(&ts.block.body, out, false);
if let Some(h) = &ts.handler {
if let Some(param) = &h.param {
collect_binding_pattern_names(&param.pattern, out);
}
collect_block_level_names_stmt(&h.body.body, out, false);
}
if let Some(f) = &ts.finalizer {
collect_block_level_names_stmt(&f.body, out, false);
}
}
Statement::LabeledStatement(ls) => {
collect_block_level_names_stmt(std::slice::from_ref(&ls.body), out, false)
}
Statement::WithStatement(ws) => collect_block_level_names_stmt(std::slice::from_ref(&ws.body), out, false),
Statement::ExportNamedDeclaration(exp) => {
if let Some(decl) = &exp.declaration {
match decl {
oxide_parser::Declaration::VariableDeclaration(vd) => {
if !matches!(vd.kind, VariableDeclarationKind::Var) && !top {
for d in &vd.declarations {
collect_binding_pattern_names(&d.id, out);
}
}
}
oxide_parser::Declaration::ClassDeclaration(cd) if !top => {
if let Some(id) = &cd.id {
out.insert(id.name.to_string());
}
}
_ => {}
}
}
}
_ => {}
}
}
}
/// 收集当前函数作用域声明的绑定名(参数 + 变量/函数声明,含嵌套 block,不含嵌套函数体)。
pub(crate) fn collect_own_binding_names(param_names: &[&str], stmts: &[Statement]) -> HashSet<String> {
let mut names = HashSet::new();
for p in param_names {
names.insert(p.to_string());
}
collect_decl_names_stmt(stmts, &mut names);
names
}
/// 递归遍历语句树收集当前函数作用域声明的绑定名(变量/函数/类/import/export,
/// 含嵌套块,不进嵌套函数体)。
pub(crate) fn collect_decl_names_stmt(stmts: &[Statement], out: &mut HashSet<String>) {
for stmt in stmts {
match stmt {
Statement::VariableDeclaration(vd) => {
for d in &vd.declarations {
collect_binding_pattern_names(&d.id, out);
}
}
Statement::FunctionDeclaration(fd) => {
if let Some(id) = &fd.id {
out.insert(id.name.to_string());
}
}
// class 名是本作用域 const 绑定:须计入 own_bindings,否则嵌套函数
// 引用类名时捕获分析缺失 → 落符号表兜底(TDZ 误报或读父寄存器残留)。
Statement::ClassDeclaration(cd) => {
if let Some(id) = &cd.id {
out.insert(id.name.to_string());
}
}
// import 绑定是模块作用域 const 绑定,须计入 own_bindings 供
// 嵌套函数 cell 捕获。
Statement::ImportDeclaration(imp) => {
if let Some(specifiers) = &imp.specifiers {
for sp in specifiers {
match sp {
oxide_parser::ImportDeclarationSpecifier::ImportSpecifier(s) => {
out.insert(s.local.name.to_string());
}
oxide_parser::ImportDeclarationSpecifier::ImportDefaultSpecifier(s) => {
out.insert(s.local.name.to_string());
}
oxide_parser::ImportDeclarationSpecifier::ImportNamespaceSpecifier(s) => {
out.insert(s.local.name.to_string());
}
}
}
}
}
Statement::ExportNamedDeclaration(exp) => {
if let Some(decl) = &exp.declaration {
match decl {
oxide_parser::Declaration::VariableDeclaration(vd) => {
for d in &vd.declarations {
collect_binding_pattern_names(&d.id, out);
}
}
oxide_parser::Declaration::FunctionDeclaration(fd) => {
if let Some(id) = &fd.id {
out.insert(id.name.to_string());
}
}
oxide_parser::Declaration::ClassDeclaration(cd) => {
if let Some(id) = &cd.id {
out.insert(id.name.to_string());
}
}
_ => {}
}
}
}
Statement::ExportDefaultDeclaration(exp) => match &exp.declaration {
oxide_parser::ExportDefaultDeclarationKind::FunctionDeclaration(fd) => {
if let Some(id) = &fd.id {
out.insert(id.name.to_string());
}
}
oxide_parser::ExportDefaultDeclarationKind::ClassDeclaration(cd) => {
if let Some(id) = &cd.id {
out.insert(id.name.to_string());
}
}
_ => {}
},
Statement::BlockStatement(b) => collect_decl_names_stmt(&b.body, out),
Statement::IfStatement(is) => {
collect_decl_names_stmt(std::slice::from_ref(&is.consequent), out);
if let Some(alt) = &is.alternate {
collect_decl_names_stmt(std::slice::from_ref(alt), out);
}
}
Statement::WhileStatement(w) => collect_decl_names_stmt(std::slice::from_ref(&w.body), out),
Statement::DoWhileStatement(d) => collect_decl_names_stmt(std::slice::from_ref(&d.body), out),
Statement::ForStatement(f) => {
if let Some(oxide_parser::ForStatementInit::VariableDeclaration(vd)) = &f.init {
for d in &vd.declarations {
if let oxide_parser::BindingPattern::BindingIdentifier(bi) = &d.id {
out.insert(bi.name.to_string());
}
}
}
collect_decl_names_stmt(std::slice::from_ref(&f.body), out);
}
// for-in / for-of 头部的 var 声明是本函数局部绑定(遮蔽外层同名),
// 须计入 own_bindings,否则闭包捕获分析会误判为捕获外层变量。
Statement::ForInStatement(fi) => {
if let oxide_parser::ForStatementLeft::VariableDeclaration(_) = &fi.left {
collect_for_left_decl_names(&fi.left, out);
}
collect_decl_names_stmt(std::slice::from_ref(&fi.body), out);
}
Statement::ForOfStatement(fo) => {
if let oxide_parser::ForStatementLeft::VariableDeclaration(_) = &fo.left {
collect_for_left_decl_names(&fo.left, out);
}
collect_decl_names_stmt(std::slice::from_ref(&fo.body), out);
}
Statement::SwitchStatement(sw) => {
for case in &sw.cases {
collect_decl_names_stmt(&case.consequent, out);
}
}
Statement::TryStatement(ts) => {
collect_decl_names_stmt(&ts.block.body, out);
if let Some(h) = &ts.handler {
// catch 参数是本函数作用域的词法绑定:计入 own_bindings,
// 嵌套函数引用它时捕获分析才会建 cell 供 upvalue 读取。
if let Some(param) = &h.param {
collect_binding_pattern_names(&param.pattern, out);
}
collect_decl_names_stmt(&h.body.body, out);
}
if let Some(f) = &ts.finalizer {
collect_decl_names_stmt(&f.body, out);
}
}
Statement::LabeledStatement(ls) => collect_decl_names_stmt(std::slice::from_ref(&ls.body), out),
Statement::WithStatement(ws) => collect_decl_names_stmt(std::slice::from_ref(&ws.body), out),
_ => {}
}
}
}