mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
perf: 作用域名收集六趟合一,函数体与模块体单趟填六输出
This commit is contained in:
Generated
+20
-20
@@ -1160,7 +1160,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_builtins"
|
||||
version = "0.16.4"
|
||||
version = "0.16.5"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"fast-float",
|
||||
@@ -1185,7 +1185,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_bytecode"
|
||||
version = "0.16.4"
|
||||
version = "0.16.5"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"oxide_log",
|
||||
@@ -1193,7 +1193,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_cfg"
|
||||
version = "0.16.4"
|
||||
version = "0.16.5"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_emit",
|
||||
@@ -1204,7 +1204,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_cli"
|
||||
version = "0.16.4"
|
||||
version = "0.16.5"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"bumpalo",
|
||||
@@ -1228,7 +1228,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_code_cache"
|
||||
version = "0.16.4"
|
||||
version = "0.16.5"
|
||||
dependencies = [
|
||||
"lru",
|
||||
"oxide_bytecode",
|
||||
@@ -1237,7 +1237,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_compiler"
|
||||
version = "0.16.4"
|
||||
version = "0.16.5"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1257,7 +1257,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_dce"
|
||||
version = "0.16.4"
|
||||
version = "0.16.5"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1271,7 +1271,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_emit"
|
||||
version = "0.16.4"
|
||||
version = "0.16.5"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"oxc_allocator",
|
||||
@@ -1286,7 +1286,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_engine"
|
||||
version = "0.16.4"
|
||||
version = "0.16.5"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_compiler",
|
||||
@@ -1298,7 +1298,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_ir"
|
||||
version = "0.16.4"
|
||||
version = "0.16.5"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_log",
|
||||
@@ -1307,7 +1307,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_kernel"
|
||||
version = "0.16.4"
|
||||
version = "0.16.5"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"dashmap",
|
||||
@@ -1321,7 +1321,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_liveness"
|
||||
version = "0.16.4"
|
||||
version = "0.16.5"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1333,7 +1333,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_log"
|
||||
version = "0.16.4"
|
||||
version = "0.16.5"
|
||||
dependencies = [
|
||||
"tracing",
|
||||
"tracing-appender",
|
||||
@@ -1342,11 +1342,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_net"
|
||||
version = "0.16.4"
|
||||
version = "0.16.5"
|
||||
|
||||
[[package]]
|
||||
name = "oxide_parser"
|
||||
version = "0.16.4"
|
||||
version = "0.16.5"
|
||||
dependencies = [
|
||||
"oxc_allocator",
|
||||
"oxc_ast",
|
||||
@@ -1361,7 +1361,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_regalloc"
|
||||
version = "0.16.4"
|
||||
version = "0.16.5"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1377,7 +1377,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_runtime_api"
|
||||
version = "0.16.4"
|
||||
version = "0.16.5"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
@@ -1390,7 +1390,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_test262"
|
||||
version = "0.16.4"
|
||||
version = "0.16.5"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_compiler",
|
||||
@@ -1410,7 +1410,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_types"
|
||||
version = "0.16.4"
|
||||
version = "0.16.5"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"dashmap",
|
||||
@@ -1423,7 +1423,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_vm"
|
||||
version = "0.16.4"
|
||||
version = "0.16.5"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"chrono",
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.16.4"
|
||||
version = "0.16.5"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
rust-version = "1.80"
|
||||
|
||||
@@ -20,10 +20,12 @@ pub(crate) use captured::collect_captured_bindings;
|
||||
pub(crate) use guard::has_nested_function;
|
||||
pub(crate) use names::collect_block_level_decl_names;
|
||||
pub(crate) use names::collect_direct_lexical_names;
|
||||
pub(crate) use names::collect_fn_scope_names;
|
||||
pub(crate) use names::collect_own_binding_names;
|
||||
pub(crate) use names::collect_top_level_function_names;
|
||||
pub(crate) use names::collect_top_level_function_names_ordered;
|
||||
pub(crate) use names::collect_var_binding_names;
|
||||
pub(crate) use names::FnScopeNames;
|
||||
pub(crate) use upvalues::collect_upvalue_names;
|
||||
|
||||
/// 收集形参(含 rest)绑定的名字集,作为本函数作用域的遮蔽集。
|
||||
|
||||
@@ -301,6 +301,277 @@ pub(crate) fn collect_own_binding_names(param_names: &[&str], stmts: &[Statement
|
||||
names
|
||||
}
|
||||
|
||||
/// 函数作用域名收集结果:单趟遍历同时填六个输出,与旧的六个独立收集函数逐位一致。
|
||||
///
|
||||
/// 字段含义与旧函数一一对应(var 提升名 / own 绑定名 / 块级声明名 / 直接子词法名 /
|
||||
/// 顶层函数名集 / 顶层函数声明序)。调用点改经本结构取各面,旧收集器保留待删。
|
||||
pub(crate) struct FnScopeNames {
|
||||
/// var 声明名(函数/程序作用域提升目标,递归进嵌套块)。
|
||||
pub(crate) var_binding_names: HashSet<String>,
|
||||
/// 当前函数作用域绑定名(参数 + 变量/函数/类/import/export 声明,含嵌套块,不含嵌套函数体)。
|
||||
pub(crate) own_binding_names: HashSet<String>,
|
||||
/// 块级声明名(块内 let/const/class、catch 参数、for 头 let/const;顶层直接子不纳)。
|
||||
pub(crate) block_level_decl_names: HashSet<String>,
|
||||
/// 直接子级词法声明名(let/const/class,入口 TDZ 占位 cell 名集)。
|
||||
pub(crate) direct_lexical_names: HashSet<String>,
|
||||
/// 直接子级函数声明名(无序集)。
|
||||
pub(crate) top_level_function_names: HashSet<String>,
|
||||
/// 直接子级函数声明名(声明序,不排序不去重)。
|
||||
pub(crate) top_level_function_names_ordered: Vec<String>,
|
||||
}
|
||||
|
||||
/// 单趟收集函数作用域六个名字输出。
|
||||
///
|
||||
/// 步骤:
|
||||
/// 1. 形参名注入 `own_binding_names`(须在遍历前,own 面是遮蔽集,形参须先入)。
|
||||
/// 2. 以 `top=true` 递归遍历顶层语句列表,直接子级填直接子词法/顶层函数名输出,
|
||||
/// 各递归层填 var/own/块级输出。
|
||||
///
|
||||
/// 边界:`param_names` 含解构叶名与 rest 名(规范 `paramNames` 口径);顶层语句列表
|
||||
/// 不递归进嵌套函数体(嵌套函数是独立编译单元)。
|
||||
/// 副作用:无(纯收集)。
|
||||
/// 注意事项:六个字段与旧六函数逐位一致,调用点切换后发射产物不变。
|
||||
pub(crate) fn collect_fn_scope_names(param_names: &[&str], stmts: &[Statement]) -> FnScopeNames {
|
||||
let mut out = FnScopeNames {
|
||||
var_binding_names: HashSet::new(),
|
||||
own_binding_names: HashSet::new(),
|
||||
block_level_decl_names: HashSet::new(),
|
||||
direct_lexical_names: HashSet::new(),
|
||||
top_level_function_names: HashSet::new(),
|
||||
top_level_function_names_ordered: Vec::new(),
|
||||
};
|
||||
for p in param_names {
|
||||
out.own_binding_names.insert(p.to_string());
|
||||
}
|
||||
collect_fn_scope_names_impl(stmts, &mut out, true);
|
||||
out
|
||||
}
|
||||
|
||||
/// 递归遍历语句树单趟填六个输出。`top` 标记当前层是否为顶层(直接子级):顶层填
|
||||
/// 直接子词法与顶层函数名输出,且顶层 let/const/class 是顶层词法绑定非块级;
|
||||
/// 各递归层(块/if/循环/switch case/try/标签/with)以 `top=false` 进入。
|
||||
fn collect_fn_scope_names_impl(stmts: &[Statement], out: &mut FnScopeNames, top: bool) {
|
||||
for stmt in stmts {
|
||||
match stmt {
|
||||
Statement::VariableDeclaration(vd) => {
|
||||
let is_var = matches!(vd.kind, VariableDeclarationKind::Var);
|
||||
// var 面:仅 var 名提升到函数作用域。
|
||||
if is_var {
|
||||
for d in &vd.declarations {
|
||||
collect_binding_pattern_names(&d.id, &mut out.var_binding_names);
|
||||
}
|
||||
}
|
||||
// own 面:全部声明种类计入当前作用域绑定。
|
||||
for d in &vd.declarations {
|
||||
collect_binding_pattern_names(&d.id, &mut out.own_binding_names);
|
||||
}
|
||||
// 块级面:非顶层的非 var(顶层词法是顶层绑定,非块级)。
|
||||
if !is_var && !top {
|
||||
for d in &vd.declarations {
|
||||
collect_binding_pattern_names(&d.id, &mut out.block_level_decl_names);
|
||||
}
|
||||
}
|
||||
// 直接子词法面:仅顶层非 var。
|
||||
if top && !is_var {
|
||||
for d in &vd.declarations {
|
||||
collect_binding_pattern_names(&d.id, &mut out.direct_lexical_names);
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::FunctionDeclaration(fd) => {
|
||||
if let Some(id) = &fd.id {
|
||||
// own 面:函数声明是当前作用域绑定。
|
||||
out.own_binding_names.insert(id.name.to_string());
|
||||
if top {
|
||||
// 顶层函数名集与声明序列表(顶层函数声明是全局 var 绑定)。
|
||||
out.top_level_function_names.insert(id.name.to_string());
|
||||
out.top_level_function_names_ordered.push(id.name.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::ClassDeclaration(cd) => {
|
||||
if let Some(id) = &cd.id {
|
||||
let name = id.name.to_string();
|
||||
// own 面:类名是本作用域 const 绑定。
|
||||
out.own_binding_names.insert(name.clone());
|
||||
if top {
|
||||
// 直接子词法面:顶层类是顶层词法绑定。
|
||||
out.direct_lexical_names.insert(name);
|
||||
} else {
|
||||
// 块级面:块内类是块作用域绑定。
|
||||
out.block_level_decl_names.insert(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::ImportDeclaration(imp) => {
|
||||
// own 面:import 绑定是模块作用域 const 绑定。
|
||||
if let Some(specifiers) = &imp.specifiers {
|
||||
for sp in specifiers {
|
||||
match sp {
|
||||
oxide_parser::ImportDeclarationSpecifier::ImportSpecifier(s) => {
|
||||
out.own_binding_names.insert(s.local.name.to_string());
|
||||
}
|
||||
oxide_parser::ImportDeclarationSpecifier::ImportDefaultSpecifier(s) => {
|
||||
out.own_binding_names.insert(s.local.name.to_string());
|
||||
}
|
||||
oxide_parser::ImportDeclarationSpecifier::ImportNamespaceSpecifier(s) => {
|
||||
out.own_binding_names.insert(s.local.name.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::ExportNamedDeclaration(exp) => {
|
||||
if let Some(decl) = &exp.declaration {
|
||||
match decl {
|
||||
oxide_parser::Declaration::VariableDeclaration(vd) => {
|
||||
let is_var = matches!(vd.kind, VariableDeclarationKind::Var);
|
||||
if is_var {
|
||||
for d in &vd.declarations {
|
||||
collect_binding_pattern_names(&d.id, &mut out.var_binding_names);
|
||||
}
|
||||
}
|
||||
for d in &vd.declarations {
|
||||
collect_binding_pattern_names(&d.id, &mut out.own_binding_names);
|
||||
}
|
||||
if !is_var && !top {
|
||||
for d in &vd.declarations {
|
||||
collect_binding_pattern_names(&d.id, &mut out.block_level_decl_names);
|
||||
}
|
||||
}
|
||||
if top && !is_var {
|
||||
for d in &vd.declarations {
|
||||
collect_binding_pattern_names(&d.id, &mut out.direct_lexical_names);
|
||||
}
|
||||
}
|
||||
}
|
||||
oxide_parser::Declaration::FunctionDeclaration(fd) => {
|
||||
if let Some(id) = &fd.id {
|
||||
out.own_binding_names.insert(id.name.to_string());
|
||||
}
|
||||
}
|
||||
oxide_parser::Declaration::ClassDeclaration(cd) => {
|
||||
if let Some(id) = &cd.id {
|
||||
let name = id.name.to_string();
|
||||
out.own_binding_names.insert(name.clone());
|
||||
if top {
|
||||
out.direct_lexical_names.insert(name);
|
||||
} else {
|
||||
out.block_level_decl_names.insert(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::ExportDefaultDeclaration(exp) => {
|
||||
match &exp.declaration {
|
||||
oxide_parser::ExportDefaultDeclarationKind::FunctionDeclaration(fd) => {
|
||||
if let Some(id) = &fd.id {
|
||||
out.own_binding_names.insert(id.name.to_string());
|
||||
}
|
||||
}
|
||||
oxide_parser::ExportDefaultDeclarationKind::ClassDeclaration(cd) => {
|
||||
if let Some(id) = &cd.id {
|
||||
let name = id.name.to_string();
|
||||
out.own_binding_names.insert(name.clone());
|
||||
// 直接子词法面仅顶层:export default class 是 lexical 绑定。
|
||||
if top {
|
||||
out.direct_lexical_names.insert(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Statement::BlockStatement(b) => collect_fn_scope_names_impl(&b.body, out, false),
|
||||
Statement::IfStatement(is) => {
|
||||
collect_fn_scope_names_impl(std::slice::from_ref(&is.consequent), out, false);
|
||||
if let Some(alt) = &is.alternate {
|
||||
collect_fn_scope_names_impl(std::slice::from_ref(alt), out, false);
|
||||
}
|
||||
}
|
||||
Statement::WhileStatement(w) => collect_fn_scope_names_impl(std::slice::from_ref(&w.body), out, false),
|
||||
Statement::DoWhileStatement(d) => collect_fn_scope_names_impl(std::slice::from_ref(&d.body), out, false),
|
||||
Statement::ForStatement(f) => {
|
||||
if let Some(oxide_parser::ForStatementInit::VariableDeclaration(vd)) = &f.init {
|
||||
let is_var = matches!(vd.kind, VariableDeclarationKind::Var);
|
||||
if is_var {
|
||||
for d in &vd.declarations {
|
||||
collect_binding_pattern_names(&d.id, &mut out.var_binding_names);
|
||||
}
|
||||
}
|
||||
// own 面:for 头声明是本函数局部绑定(仅标识符形态,与旧趟一致)。
|
||||
for d in &vd.declarations {
|
||||
if let oxide_parser::BindingPattern::BindingIdentifier(bi) = &d.id {
|
||||
out.own_binding_names.insert(bi.name.to_string());
|
||||
}
|
||||
}
|
||||
// 块级面:for 头 let/const 是循环作用域绑定(各层均收集)。
|
||||
if !is_var {
|
||||
for d in &vd.declarations {
|
||||
collect_binding_pattern_names(&d.id, &mut out.block_level_decl_names);
|
||||
}
|
||||
}
|
||||
}
|
||||
collect_fn_scope_names_impl(std::slice::from_ref(&f.body), out, false);
|
||||
}
|
||||
Statement::ForInStatement(fi) => {
|
||||
if let oxide_parser::ForStatementLeft::VariableDeclaration(vd) = &fi.left {
|
||||
let is_var = matches!(vd.kind, VariableDeclarationKind::Var);
|
||||
if is_var {
|
||||
// 仅 var 头名提升到函数作用域,let/const 头名是迭代级绑定。
|
||||
collect_for_left_decl_names(&fi.left, &mut out.var_binding_names);
|
||||
}
|
||||
collect_for_left_decl_names(&fi.left, &mut out.own_binding_names);
|
||||
if !is_var {
|
||||
collect_for_left_decl_names(&fi.left, &mut out.block_level_decl_names);
|
||||
}
|
||||
}
|
||||
collect_fn_scope_names_impl(std::slice::from_ref(&fi.body), out, false);
|
||||
}
|
||||
Statement::ForOfStatement(fo) => {
|
||||
if let oxide_parser::ForStatementLeft::VariableDeclaration(vd) = &fo.left {
|
||||
let is_var = matches!(vd.kind, VariableDeclarationKind::Var);
|
||||
if is_var {
|
||||
collect_for_left_decl_names(&fo.left, &mut out.var_binding_names);
|
||||
}
|
||||
collect_for_left_decl_names(&fo.left, &mut out.own_binding_names);
|
||||
if !is_var {
|
||||
collect_for_left_decl_names(&fo.left, &mut out.block_level_decl_names);
|
||||
}
|
||||
}
|
||||
collect_fn_scope_names_impl(std::slice::from_ref(&fo.body), out, false);
|
||||
}
|
||||
Statement::SwitchStatement(sw) => {
|
||||
for case in &sw.cases {
|
||||
collect_fn_scope_names_impl(&case.consequent, out, false);
|
||||
}
|
||||
}
|
||||
Statement::TryStatement(ts) => {
|
||||
// catch 参数是本作用域的词法绑定:own 与块级两面均计入。
|
||||
if let Some(h) = &ts.handler {
|
||||
if let Some(param) = &h.param {
|
||||
collect_binding_pattern_names(¶m.pattern, &mut out.own_binding_names);
|
||||
collect_binding_pattern_names(¶m.pattern, &mut out.block_level_decl_names);
|
||||
}
|
||||
collect_fn_scope_names_impl(&h.body.body, out, false);
|
||||
}
|
||||
collect_fn_scope_names_impl(&ts.block.body, out, false);
|
||||
if let Some(f) = &ts.finalizer {
|
||||
collect_fn_scope_names_impl(&f.body, out, false);
|
||||
}
|
||||
}
|
||||
Statement::LabeledStatement(ls) => {
|
||||
collect_fn_scope_names_impl(std::slice::from_ref(&ls.body), out, false)
|
||||
}
|
||||
Statement::WithStatement(ws) => collect_fn_scope_names_impl(std::slice::from_ref(&ws.body), out, false),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 递归遍历语句树收集当前函数作用域声明的绑定名(变量/函数/类/import/export,
|
||||
/// 含嵌套块,不进嵌套函数体)。
|
||||
pub(crate) fn collect_decl_names_stmt(stmts: &[Statement], out: &mut HashSet<String>) {
|
||||
@@ -435,3 +706,140 @@ pub(crate) fn collect_decl_names_stmt(stmts: &[Statement], out: &mut HashSet<Str
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
/// 夹具:parse 源串(脚本口径)后,六输出逐一断言新单趟与旧六函数逐位一致。
|
||||
fn assert_bitwise(src: &str, params: &[&str]) {
|
||||
let alloc = oxide_parser::Allocator::default();
|
||||
let program =
|
||||
oxide_parser::parse(&alloc, src).unwrap_or_else(|e| panic!("parse 失败 {src:?}: {e:?}"));
|
||||
let body = &program.body;
|
||||
|
||||
let names = collect_fn_scope_names(params, body);
|
||||
assert_eq!(names.var_binding_names, collect_var_binding_names(body), "var 面漂移:{src:?}");
|
||||
assert_eq!(
|
||||
names.own_binding_names,
|
||||
collect_own_binding_names(params, body),
|
||||
"own 面漂移:{src:?}"
|
||||
);
|
||||
assert_eq!(
|
||||
names.block_level_decl_names,
|
||||
collect_block_level_decl_names(body),
|
||||
"块级面漂移:{src:?}"
|
||||
);
|
||||
assert_eq!(
|
||||
names.direct_lexical_names,
|
||||
collect_direct_lexical_names(body),
|
||||
"直接子词法面漂移:{src:?}"
|
||||
);
|
||||
assert_eq!(
|
||||
names.top_level_function_names,
|
||||
collect_top_level_function_names(body),
|
||||
"顶层函数名面漂移:{src:?}"
|
||||
);
|
||||
assert_eq!(
|
||||
names.top_level_function_names_ordered,
|
||||
collect_top_level_function_names_ordered(body),
|
||||
"顶层函数声明序漂移:{src:?}"
|
||||
);
|
||||
}
|
||||
|
||||
/// 夹具:parse 源串(模块口径)后,六输出逐一断言新单趟与旧六函数逐位一致。
|
||||
fn assert_bitwise_module(src: &str, params: &[&str]) {
|
||||
let alloc = oxide_parser::Allocator::default();
|
||||
let program = oxide_parser::parse_module(&alloc, src)
|
||||
.unwrap_or_else(|e| panic!("parse_module 失败 {src:?}: {e:?}"));
|
||||
let body = &program.body;
|
||||
|
||||
let names = collect_fn_scope_names(params, body);
|
||||
assert_eq!(names.var_binding_names, collect_var_binding_names(body), "var 面漂移:{src:?}");
|
||||
assert_eq!(
|
||||
names.own_binding_names,
|
||||
collect_own_binding_names(params, body),
|
||||
"own 面漂移:{src:?}"
|
||||
);
|
||||
assert_eq!(
|
||||
names.block_level_decl_names,
|
||||
collect_block_level_decl_names(body),
|
||||
"块级面漂移:{src:?}"
|
||||
);
|
||||
assert_eq!(
|
||||
names.direct_lexical_names,
|
||||
collect_direct_lexical_names(body),
|
||||
"直接子词法面漂移:{src:?}"
|
||||
);
|
||||
assert_eq!(
|
||||
names.top_level_function_names,
|
||||
collect_top_level_function_names(body),
|
||||
"顶层函数名面漂移:{src:?}"
|
||||
);
|
||||
assert_eq!(
|
||||
names.top_level_function_names_ordered,
|
||||
collect_top_level_function_names_ordered(body),
|
||||
"顶层函数声明序漂移:{src:?}"
|
||||
);
|
||||
}
|
||||
|
||||
/// 顶层声明面:var/let/const/函数/类声明与解构 pattern 叶名。
|
||||
#[test]
|
||||
fn fn_scope_names_bitwise_parity_declarations() {
|
||||
assert_bitwise("var a; let b = 1; const c = 2; function f() {} class K {}", &[]);
|
||||
assert_bitwise("var a = {x: 1, y: [z]}; let [p, ...q] = arr; let {m, n: o} = obj;", &[]);
|
||||
assert_bitwise("function f() { var inner; } function g() {} var f2;", &[]);
|
||||
assert_bitwise("var a; var a; function f() {} function f() {}", &[]);
|
||||
}
|
||||
|
||||
/// 控制流面:if/while/do-while/for/for-in/for-of/switch/try/labeled/with 各分支。
|
||||
#[test]
|
||||
fn fn_scope_names_bitwise_parity_control_flow() {
|
||||
assert_bitwise("if (x) { var a; let b; } else { var c; let d; }", &[]);
|
||||
assert_bitwise("while (x) { var a; let b; } do { var c; } while (x);", &[]);
|
||||
assert_bitwise("for (var i = 0; i < n; i++) { var a; let b; }", &[]);
|
||||
assert_bitwise("for (let j of it) { var a; } for (var k in obj) { let b; }", &[]);
|
||||
assert_bitwise("switch (x) { case 1: { var a; let b; } default: { var c; } }", &[]);
|
||||
assert_bitwise("try { var a; } catch (e) { let b; } finally { var c; }", &[]);
|
||||
assert_bitwise("try { var a; } catch { let b; }", &[]);
|
||||
assert_bitwise("L: { var a; let b; }", &[]);
|
||||
assert_bitwise("with (obj) { var a; let b; }", &[]);
|
||||
}
|
||||
|
||||
/// 嵌套块面:块内 let/const/class 是块级绑定,顶层直接子不纳。
|
||||
#[test]
|
||||
fn fn_scope_names_bitwise_parity_nested_blocks() {
|
||||
assert_bitwise("{ { var a; let b; class K {} } }", &[]);
|
||||
assert_bitwise("if (x) { { let a; const b = 1; } }", &[]);
|
||||
assert_bitwise("var a; { let b; } function f() { var c; }", &[]);
|
||||
assert_bitwise("if (x) while (y) { let a; } for (var i;;) { const b = 1; }", &[]);
|
||||
}
|
||||
|
||||
/// 形参注入面:param_names 进 own 面,须与旧 collect_own_binding_names 同口径。
|
||||
#[test]
|
||||
fn fn_scope_names_bitwise_parity_params_injection() {
|
||||
assert_bitwise("var p; let q; function f() {}", &["p", "q", "r"]);
|
||||
assert_bitwise("var x = 1;", &["x", "y"]);
|
||||
assert_bitwise("function f() { var p; }", &["p"]);
|
||||
}
|
||||
|
||||
/// 模块声明面:import/export 包装的声明计入各面(模块口径 parse)。
|
||||
#[test]
|
||||
fn fn_scope_names_bitwise_parity_module_decls() {
|
||||
assert_bitwise_module("import a from 'm'; import * as ns from 'm'; import { b, c as d } from 'm';", &[]);
|
||||
assert_bitwise_module("export var e = 1; export let f = 2; export const g = 3;", &[]);
|
||||
assert_bitwise_module("export function h() {} export class J {}", &[]);
|
||||
assert_bitwise_module("export default function named() {}", &[]);
|
||||
assert_bitwise_module("export default class K {}", &[]);
|
||||
assert_bitwise_module("import a from 'm'; export var b = 1; function c() {}", &[]);
|
||||
assert_bitwise_module("export { x } from 'n';", &[]);
|
||||
}
|
||||
|
||||
/// for 头面:var/let/const 头名分面归属(var 提升、let/const 块级)。
|
||||
#[test]
|
||||
fn fn_scope_names_bitwise_parity_for_heads() {
|
||||
assert_bitwise("for (var [a, b] of it) {} for (let {x, ...y} in obj) {}", &[]);
|
||||
assert_bitwise("for (var i;;) {} for (let j;;) {} for (const k = 0;;) {}", &[]);
|
||||
assert_bitwise("for (var i = 0;;) { for (let j;;) { var a; } }", &[]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,8 +14,8 @@ use oxide_ir::IRFunction;
|
||||
use oxide_parser::{Expression, Statement, VariableDeclarationKind};
|
||||
|
||||
use crate::capture::{
|
||||
collect_binding_pattern_names, collect_captured_bindings, collect_direct_lexical_names, collect_own_binding_names,
|
||||
collect_upvalue_names, collect_var_binding_names, has_nested_function,
|
||||
collect_binding_pattern_names, collect_captured_bindings, collect_fn_scope_names, collect_upvalue_names,
|
||||
has_nested_function, FnScopeNames,
|
||||
};
|
||||
use crate::compile_ctx::{CompileCtx, FieldBuffer};
|
||||
use crate::symbol_table::{Binding, ScopeKind};
|
||||
@@ -434,6 +434,11 @@ impl Emitter {
|
||||
// 让 next_reg 与 builtin 槽位对齐,参数在 builtin 槽之后分配。
|
||||
ctx.reset_regs();
|
||||
|
||||
// 函数作用域六个名字面单趟收集(形参名先注入 own 面):本函数体编译链
|
||||
// 各调用点(参数 prologue / builtin 排除 / 入口实例化)共用此结果。
|
||||
let param_name_refs: Vec<&str> = param_specs.iter().map(|s| s.register_name()).collect();
|
||||
let scope_names = collect_fn_scope_names(¶m_name_refs, body_stmts);
|
||||
|
||||
let param_base = self.emit_params_prologue(
|
||||
param_specs,
|
||||
body_stmts,
|
||||
@@ -443,6 +448,7 @@ impl Emitter {
|
||||
extra_capture_exprs,
|
||||
extra_upvalue_names,
|
||||
name,
|
||||
&scope_names,
|
||||
)?;
|
||||
// 实例字段 computed key 数组所在 upvalue 下标,供字段初始化 emit 定位。
|
||||
ctx.field_keys_uv = ctx
|
||||
@@ -456,7 +462,7 @@ impl Emitter {
|
||||
|
||||
// 预注册 builtin 引用(先于任何临时寄存器),builtin 槽不与被复用的临时值冲突。
|
||||
// 函数体直接子级词法声明名排除登记(顶层词法遮蔽同口径,见 program.rs)。
|
||||
let lexical_excluded = collect_direct_lexical_names(body_stmts);
|
||||
let lexical_excluded = scope_names.direct_lexical_names.clone();
|
||||
self.pre_register_builtin_references(body_stmts, &lexical_excluded, &mut ctx);
|
||||
|
||||
// 预声明 `var` 名,使首个 sub-pass 中提升的函数声明能解析其闭包引用的外层 var。
|
||||
@@ -488,7 +494,7 @@ impl Emitter {
|
||||
// 不发射定义指令,声明点对已绑定名又跳过 undefined 写,缺失入口写会让首次
|
||||
// 写入前的读取取到调用方遗留的寄存器值。捕获名已由参数 prologue 的
|
||||
// MAKE_CELL(undefined) 实例化,此处只补未捕获名。
|
||||
self.instantiate_var_bindings(body_stmts, &mut ctx);
|
||||
self.instantiate_var_bindings(body_stmts, &mut ctx, &scope_names);
|
||||
|
||||
// 被捕获的函数名绑定同样建 cell(MAKE_CELL):值源是帧槽写入已置位的
|
||||
// 名槽寄存器(函数对象),非 undefined。名槽寄存器此时已知(非抑制面
|
||||
@@ -655,7 +661,7 @@ impl Emitter {
|
||||
fn emit_params_prologue<'a>(
|
||||
&self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx,
|
||||
ctx: &mut CompileCtx, body_context: FunctionBodyContext, extra_capture_exprs: &[&'a Expression<'a>],
|
||||
extra_upvalue_names: &[(String, u8)], name: Option<&str>,
|
||||
extra_upvalue_names: &[(String, u8)], name: Option<&str>, scope_names: &FnScopeNames,
|
||||
) -> Result<u32, String> {
|
||||
ctx.push_scope_with_kind(ScopeKind::FunctionScope);
|
||||
let param_base = ctx.next_reg;
|
||||
@@ -696,7 +702,7 @@ impl Emitter {
|
||||
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 = collect_own_binding_names(¶m_names, body_stmts);
|
||||
ctx.own_bindings = scope_names.own_binding_names.clone();
|
||||
for spec in param_specs {
|
||||
if let ParamSpec::Pattern { pattern, .. } = spec {
|
||||
collect_binding_pattern_names(pattern, &mut ctx.own_bindings);
|
||||
@@ -723,7 +729,7 @@ impl Emitter {
|
||||
// 名登记须先于 set_captured_bindings:嵌套函数捕获名分析依赖 own_bindings
|
||||
// 完整(名被捕获时须识别为本函数绑定并建 cell)。
|
||||
if let Some(fn_name) = name {
|
||||
let var_names = collect_var_binding_names(body_stmts);
|
||||
let var_names = &scope_names.var_binding_names;
|
||||
let suppressed = ctx.param_names.contains(fn_name)
|
||||
|| var_names.contains(fn_name)
|
||||
|| (fn_name == "arguments" && arguments_reg.is_some());
|
||||
@@ -1005,7 +1011,7 @@ impl Emitter {
|
||||
// 则取调用方寄存器残留。参数与 arguments 已在上方初始化(跳过以免覆盖参数
|
||||
// 值);let/const/class 保持 TDZ 语义不动。声明语句的 MAKE_CELL 按占位更新
|
||||
// 语义覆盖此初值。
|
||||
let mut captured_entry_names = collect_var_binding_names(body_stmts);
|
||||
let mut captured_entry_names = scope_names.var_binding_names.clone();
|
||||
// 块级函数外层 var 名与 instantiate_var_bindings 同源并入;抑制名(形参/
|
||||
// 词法声明同名)无外层绑定,不并入。抑制集在此独立计算:本循环早于函数体
|
||||
// 的 block_fn_suppressed 构建。
|
||||
@@ -1046,10 +1052,12 @@ impl Emitter {
|
||||
// 运行时抛真 TDZ;声明语句的 MAKE_CELL 按占位更新语义原位翻转。名集只取
|
||||
// 直接子级(块级名不提升到函数作用域,与块内重执行 cell 族零交集),
|
||||
// 排序保证发射序跨进程稳定。
|
||||
let mut lex_names: Vec<String> = collect_direct_lexical_names(body_stmts)
|
||||
.into_iter()
|
||||
.filter(|n| !param_names.contains(&n.as_str()) && n != "arguments")
|
||||
.filter(|n| ctx.captured_bindings.contains_key(n))
|
||||
let mut lex_names: Vec<String> = scope_names
|
||||
.direct_lexical_names
|
||||
.iter()
|
||||
.filter(|n| !param_names.contains(&n.as_str()) && n != &"arguments")
|
||||
.filter(|n| ctx.captured_bindings.contains_key(n.as_str()))
|
||||
.cloned()
|
||||
.collect();
|
||||
lex_names.sort();
|
||||
if !lex_names.is_empty() {
|
||||
@@ -1085,8 +1093,8 @@ impl Emitter {
|
||||
/// var;被形参/词法同名抑制的名字无外层绑定,不并入。直接子标签函数声明由
|
||||
/// 函数入口单独物化闭包,不并入。
|
||||
/// - 符号表查不到的名字(如解构 pattern 叶名未被预声明)跳过,不报错。
|
||||
fn instantiate_var_bindings(&self, body_stmts: &[Statement], ctx: &mut CompileCtx) {
|
||||
let mut name_set = collect_var_binding_names(body_stmts);
|
||||
fn instantiate_var_bindings(&self, body_stmts: &[Statement], ctx: &mut CompileCtx, scope_names: &FnScopeNames) {
|
||||
let mut name_set = scope_names.var_binding_names.clone();
|
||||
|
||||
// 块级函数外层 var 绑定同样只预声明不发射定义指令,缺失入口写会让块前读取
|
||||
// 取到调用方残留;入口写须并入(strict 与抑制名除外)。
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::path::Path;
|
||||
|
||||
use crate::capture::{collect_captured_bindings, collect_direct_lexical_names, collect_own_binding_names};
|
||||
use crate::capture::{collect_captured_bindings, collect_fn_scope_names};
|
||||
use crate::expr::call::pack_arg_regs;
|
||||
use crate::{CompileCtx, Emitter};
|
||||
use oxc_allocator::Box;
|
||||
@@ -451,17 +451,21 @@ impl Emitter {
|
||||
) -> Result<(), String> {
|
||||
let body = &program.body;
|
||||
|
||||
// 模块作用域六个名字面单趟收集(模块顶层无形参,param_names 传空):
|
||||
// builtin 排除 / own 绑定 / 入口 var 与词法实例化各调用点共用此结果。
|
||||
let scope_names = collect_fn_scope_names(&[], body);
|
||||
|
||||
// —— 预声明(镜像 emit_program;import/export 包装的声明也计入 hoisting)——
|
||||
self.predeclare_function_declarations(body, ctx);
|
||||
// 模块顶层词法声明名排除镜像登记(词法绑定遮蔽同名全局属性,同 program.rs)。
|
||||
let lexical_excluded = collect_direct_lexical_names(body);
|
||||
let lexical_excluded = scope_names.direct_lexical_names.clone();
|
||||
self.pre_register_builtin_references(body, &lexical_excluded, ctx);
|
||||
self.predeclare_var_declarations(body, ctx);
|
||||
// 模块 lexical 声明入模块环境(非全局对象),不做受限全局名检查。
|
||||
let _ = self.predeclare_lexical_declarations(body, ctx);
|
||||
|
||||
// 闭包捕获分析(import 绑定名纳入 own_bindings,供嵌套函数 cell 捕获)。
|
||||
ctx.own_bindings = collect_own_binding_names(&[], body);
|
||||
ctx.own_bindings = scope_names.own_binding_names.clone();
|
||||
ctx.set_captured_bindings(collect_captured_bindings(body, &[], &ctx.own_bindings));
|
||||
// 模块顶层函数级绑定 cell 索引回填:预声明已完成,绑定已齐。
|
||||
ctx.backfill_captured_cell_idxs();
|
||||
@@ -834,10 +838,12 @@ impl Emitter {
|
||||
// var 名在模块入口统一 MAKE_CELL(undefined),与脚本顶层实例化同语义。——
|
||||
self.reconcile_alias_captures(ctx);
|
||||
{
|
||||
let mut var_names: Vec<String> = crate::capture::collect_var_binding_names(body)
|
||||
.into_iter()
|
||||
let mut var_names: Vec<String> = scope_names
|
||||
.var_binding_names
|
||||
.iter()
|
||||
.filter(|n| !ctx.param_names.contains(n.as_str()))
|
||||
.filter(|n| ctx.captured_bindings.contains_key(n))
|
||||
.filter(|n| ctx.captured_bindings.contains_key(n.as_str()))
|
||||
.cloned()
|
||||
.collect();
|
||||
var_names.sort();
|
||||
if !var_names.is_empty() {
|
||||
@@ -857,10 +863,12 @@ impl Emitter {
|
||||
// 既有预注册保持未初始化 TDZ(命名空间对象面,按导出名),入口 cell
|
||||
// 只覆盖被嵌套函数捕获的名(按捕获名),两面名集独立。声明语句的
|
||||
// MAKE_CELL 按占位更新语义原位翻转;直接子级 only,块级名不提升。
|
||||
let mut lex_names: Vec<String> = crate::capture::collect_direct_lexical_names(body)
|
||||
.into_iter()
|
||||
let mut lex_names: Vec<String> = scope_names
|
||||
.direct_lexical_names
|
||||
.iter()
|
||||
.filter(|n| !ctx.param_names.contains(n.as_str()))
|
||||
.filter(|n| ctx.captured_bindings.contains_key(n))
|
||||
.filter(|n| ctx.captured_bindings.contains_key(n.as_str()))
|
||||
.cloned()
|
||||
.collect();
|
||||
lex_names.sort();
|
||||
if !lex_names.is_empty() {
|
||||
|
||||
Reference in New Issue
Block a user