mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
refactor: 拆分闭包分析与预扫描模块,拆分函数体编译子步骤
This commit is contained in:
@@ -0,0 +1,518 @@
|
||||
use std::collections::{BTreeMap, HashSet};
|
||||
|
||||
use oxide_bytecode::module::UpvalueCapture;
|
||||
use oxide_parser::{Expression, Statement};
|
||||
|
||||
use crate::compiler::Compiler;
|
||||
|
||||
impl Compiler {
|
||||
|
||||
fn collect_fn_param_names(&self, params: &oxide_parser::FormalParameters) -> HashSet<String> {
|
||||
let mut names = HashSet::new();
|
||||
for p in ¶ms.items {
|
||||
if let oxide_parser::BindingPattern::BindingIdentifier(bi) = &p.pattern {
|
||||
names.insert(bi.name.to_string());
|
||||
}
|
||||
}
|
||||
names
|
||||
}
|
||||
|
||||
/// 收集当前函数作用域声明的绑定名(参数 + 变量/函数声明,含嵌套 block,不含嵌套函数体)。
|
||||
pub(crate) fn collect_own_binding_names(&self, param_names: &[&str], stmts: &[Statement]) -> HashSet<String> {
|
||||
let mut names = HashSet::new();
|
||||
for p in param_names {
|
||||
names.insert(p.to_string());
|
||||
}
|
||||
self.collect_decl_names_stmt(stmts, &mut names);
|
||||
names
|
||||
}
|
||||
|
||||
fn collect_decl_names_stmt(&self, stmts: &[Statement], out: &mut HashSet<String>) {
|
||||
for stmt in stmts {
|
||||
match stmt {
|
||||
Statement::VariableDeclaration(vd) => {
|
||||
for d in &vd.declarations {
|
||||
if let oxide_parser::BindingPattern::BindingIdentifier(bi) = &d.id {
|
||||
out.insert(bi.name.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::FunctionDeclaration(fd) => {
|
||||
if let Some(id) = &fd.id {
|
||||
out.insert(id.name.to_string());
|
||||
}
|
||||
}
|
||||
Statement::BlockStatement(b) => self.collect_decl_names_stmt(&b.body, out),
|
||||
Statement::IfStatement(is) => {
|
||||
self.collect_decl_names_stmt(std::slice::from_ref(&is.consequent), out);
|
||||
if let Some(alt) = &is.alternate {
|
||||
self.collect_decl_names_stmt(std::slice::from_ref(alt), out);
|
||||
}
|
||||
}
|
||||
Statement::WhileStatement(w) => self.collect_decl_names_stmt(std::slice::from_ref(&w.body), out),
|
||||
Statement::DoWhileStatement(d) => self.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());
|
||||
}
|
||||
}
|
||||
}
|
||||
self.collect_decl_names_stmt(std::slice::from_ref(&f.body), out);
|
||||
}
|
||||
Statement::SwitchStatement(sw) => {
|
||||
for case in &sw.cases {
|
||||
self.collect_decl_names_stmt(&case.consequent, out);
|
||||
}
|
||||
}
|
||||
Statement::TryStatement(ts) => {
|
||||
self.collect_decl_names_stmt(&ts.block.body, out);
|
||||
if let Some(h) = &ts.handler {
|
||||
self.collect_decl_names_stmt(&h.body.body, out);
|
||||
}
|
||||
if let Some(f) = &ts.finalizer {
|
||||
self.collect_decl_names_stmt(&f.body, out);
|
||||
}
|
||||
}
|
||||
Statement::LabeledStatement(ls) => self.collect_decl_names_stmt(std::slice::from_ref(&ls.body), out),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 扫描 stmts 内(含任意深度嵌套函数)对 `ref_set` 的引用,写入 out。
|
||||
/// 递归进入嵌套函数时累加其局部绑定为遮蔽集,避免把内层局部误判为捕获。
|
||||
fn collect_capture_names(&self, stmts: &[Statement], ref_set: &HashSet<String>, out: &mut HashSet<String>) {
|
||||
let shadow = HashSet::new();
|
||||
self.collect_capture_names_shadowed(stmts, ref_set, &shadow, out);
|
||||
}
|
||||
|
||||
fn collect_capture_names_shadowed(
|
||||
&self, stmts: &[Statement], ref_set: &HashSet<String>, shadow: &HashSet<String>, out: &mut HashSet<String>,
|
||||
) {
|
||||
for stmt in stmts {
|
||||
self.collect_capture_names_stmt(stmt, ref_set, shadow, out);
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_capture_names_stmt(
|
||||
&self, stmt: &Statement, ref_set: &HashSet<String>, shadow: &HashSet<String>, out: &mut HashSet<String>,
|
||||
) {
|
||||
match stmt {
|
||||
Statement::ExpressionStatement(es) => self.collect_capture_names_expr(&es.expression, ref_set, shadow, out),
|
||||
Statement::ReturnStatement(rs) => {
|
||||
if let Some(a) = &rs.argument {
|
||||
self.collect_capture_names_expr(a, ref_set, shadow, out);
|
||||
}
|
||||
}
|
||||
Statement::VariableDeclaration(vd) => {
|
||||
for d in &vd.declarations {
|
||||
if let Some(init) = &d.init {
|
||||
self.collect_capture_names_expr(init, ref_set, shadow, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::FunctionDeclaration(fd) => {
|
||||
let body: &[Statement] = fd.body.as_ref().map(|b| &b.statements[..]).unwrap_or(&[]);
|
||||
let mut inner = shadow.clone();
|
||||
inner.extend(self.collect_fn_param_names(&fd.params));
|
||||
inner.extend(self.collect_own_binding_names(&[], body));
|
||||
self.collect_capture_names_shadowed(body, ref_set, &inner, out);
|
||||
}
|
||||
Statement::IfStatement(is) => {
|
||||
self.collect_capture_names_expr(&is.test, ref_set, shadow, out);
|
||||
self.collect_capture_names_stmt(&is.consequent, ref_set, shadow, out);
|
||||
if let Some(alt) = &is.alternate {
|
||||
self.collect_capture_names_stmt(alt, ref_set, shadow, out);
|
||||
}
|
||||
}
|
||||
Statement::ForStatement(fs) => {
|
||||
if let Some(init) = &fs.init {
|
||||
if let Some(e) = init.as_expression() {
|
||||
self.collect_capture_names_expr(e, ref_set, shadow, out);
|
||||
}
|
||||
if let oxide_parser::ForStatementInit::VariableDeclaration(vd) = init {
|
||||
for d in &vd.declarations {
|
||||
if let Some(i) = &d.init {
|
||||
self.collect_capture_names_expr(i, ref_set, shadow, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(t) = &fs.test {
|
||||
self.collect_capture_names_expr(t, ref_set, shadow, out);
|
||||
}
|
||||
if let Some(u) = &fs.update {
|
||||
self.collect_capture_names_expr(u, ref_set, shadow, out);
|
||||
}
|
||||
self.collect_capture_names_stmt(&fs.body, ref_set, shadow, out);
|
||||
}
|
||||
Statement::WhileStatement(w) => {
|
||||
self.collect_capture_names_expr(&w.test, ref_set, shadow, out);
|
||||
self.collect_capture_names_stmt(&w.body, ref_set, shadow, out);
|
||||
}
|
||||
Statement::DoWhileStatement(d) => {
|
||||
self.collect_capture_names_stmt(&d.body, ref_set, shadow, out);
|
||||
self.collect_capture_names_expr(&d.test, ref_set, shadow, out);
|
||||
}
|
||||
Statement::ForInStatement(fi) => {
|
||||
self.collect_capture_names_expr(&fi.right, ref_set, shadow, out);
|
||||
self.collect_capture_names_stmt(&fi.body, ref_set, shadow, out);
|
||||
}
|
||||
Statement::ForOfStatement(fo) => {
|
||||
self.collect_capture_names_expr(&fo.right, ref_set, shadow, out);
|
||||
self.collect_capture_names_stmt(&fo.body, ref_set, shadow, out);
|
||||
}
|
||||
Statement::BlockStatement(b) => self.collect_capture_names_shadowed(&b.body, ref_set, shadow, out),
|
||||
Statement::TryStatement(ts) => {
|
||||
for s in &ts.block.body {
|
||||
self.collect_capture_names_stmt(s, ref_set, shadow, out);
|
||||
}
|
||||
if let Some(h) = &ts.handler {
|
||||
for s in &h.body.body {
|
||||
self.collect_capture_names_stmt(s, ref_set, shadow, out);
|
||||
}
|
||||
}
|
||||
if let Some(f) = &ts.finalizer {
|
||||
for s in &f.body {
|
||||
self.collect_capture_names_stmt(s, ref_set, shadow, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::ThrowStatement(ts) => self.collect_capture_names_expr(&ts.argument, ref_set, shadow, out),
|
||||
Statement::SwitchStatement(sw) => {
|
||||
self.collect_capture_names_expr(&sw.discriminant, ref_set, shadow, out);
|
||||
for case in &sw.cases {
|
||||
for s in &case.consequent {
|
||||
self.collect_capture_names_stmt(s, ref_set, shadow, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::LabeledStatement(ls) => self.collect_capture_names_stmt(&ls.body, ref_set, shadow, out),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_capture_names_expr(
|
||||
&self, expr: &Expression, ref_set: &HashSet<String>, shadow: &HashSet<String>, out: &mut HashSet<String>,
|
||||
) {
|
||||
match expr {
|
||||
Expression::Identifier(id) => {
|
||||
let name = id.name.as_str();
|
||||
if ref_set.contains(name) && !shadow.contains(name) {
|
||||
out.insert(id.name.to_string());
|
||||
}
|
||||
}
|
||||
Expression::AssignmentExpression(ae) => {
|
||||
if let oxide_parser::AssignmentTarget::AssignmentTargetIdentifier(ati) = &ae.left {
|
||||
let name = ati.name.as_str();
|
||||
if ref_set.contains(name) && !shadow.contains(name) {
|
||||
out.insert(ati.name.to_string());
|
||||
}
|
||||
}
|
||||
self.collect_capture_names_expr(&ae.right, ref_set, shadow, out);
|
||||
}
|
||||
Expression::UpdateExpression(ue) => {
|
||||
if let oxide_parser::SimpleAssignmentTarget::AssignmentTargetIdentifier(ati) = &ue.argument {
|
||||
let name = ati.name.as_str();
|
||||
if ref_set.contains(name) && !shadow.contains(name) {
|
||||
out.insert(ati.name.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
Expression::FunctionExpression(fe) => {
|
||||
let body: &[Statement] = fe.body.as_ref().map(|b| &b.statements[..]).unwrap_or(&[]);
|
||||
let mut inner = shadow.clone();
|
||||
inner.extend(self.collect_fn_param_names(&fe.params));
|
||||
inner.extend(self.collect_own_binding_names(&[], body));
|
||||
self.collect_capture_names_shadowed(body, ref_set, &inner, out);
|
||||
}
|
||||
Expression::ArrowFunctionExpression(ae) => {
|
||||
let mut inner = shadow.clone();
|
||||
inner.extend(self.collect_fn_param_names(&ae.params));
|
||||
inner.extend(self.collect_own_binding_names(&[], &ae.body.statements));
|
||||
self.collect_capture_names_shadowed(&ae.body.statements, ref_set, &inner, out);
|
||||
}
|
||||
Expression::BinaryExpression(be) => {
|
||||
self.collect_capture_names_expr(&be.left, ref_set, shadow, out);
|
||||
self.collect_capture_names_expr(&be.right, ref_set, shadow, out);
|
||||
}
|
||||
Expression::UnaryExpression(ue) => self.collect_capture_names_expr(&ue.argument, ref_set, shadow, out),
|
||||
Expression::CallExpression(ce) => {
|
||||
self.collect_capture_names_expr(&ce.callee, ref_set, shadow, out);
|
||||
for a in &ce.arguments {
|
||||
if let Some(e) = a.as_expression() {
|
||||
self.collect_capture_names_expr(e, ref_set, shadow, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
Expression::NewExpression(ne) => {
|
||||
self.collect_capture_names_expr(&ne.callee, ref_set, shadow, out);
|
||||
for a in &ne.arguments {
|
||||
if let Some(e) = a.as_expression() {
|
||||
self.collect_capture_names_expr(e, ref_set, shadow, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
Expression::SequenceExpression(se) => {
|
||||
for e in &se.expressions {
|
||||
self.collect_capture_names_expr(e, ref_set, shadow, out);
|
||||
}
|
||||
}
|
||||
Expression::ConditionalExpression(ce) => {
|
||||
self.collect_capture_names_expr(&ce.test, ref_set, shadow, out);
|
||||
self.collect_capture_names_expr(&ce.consequent, ref_set, shadow, out);
|
||||
self.collect_capture_names_expr(&ce.alternate, ref_set, shadow, out);
|
||||
}
|
||||
Expression::ArrayExpression(ae) => {
|
||||
for e in &ae.elements {
|
||||
if let Some(e) = e.as_expression() {
|
||||
self.collect_capture_names_expr(e, ref_set, shadow, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
Expression::LogicalExpression(le) => {
|
||||
self.collect_capture_names_expr(&le.left, ref_set, shadow, out);
|
||||
self.collect_capture_names_expr(&le.right, ref_set, shadow, out);
|
||||
}
|
||||
Expression::ComputedMemberExpression(m) => {
|
||||
self.collect_capture_names_expr(&m.object, ref_set, shadow, out);
|
||||
self.collect_capture_names_expr(&m.expression, ref_set, shadow, out);
|
||||
}
|
||||
Expression::StaticMemberExpression(m) => self.collect_capture_names_expr(&m.object, ref_set, shadow, out),
|
||||
Expression::PrivateFieldExpression(m) => self.collect_capture_names_expr(&m.object, ref_set, shadow, out),
|
||||
Expression::ParenthesizedExpression(p) => self.collect_capture_names_expr(&p.expression, ref_set, shadow, out),
|
||||
Expression::TemplateLiteral(tl) => {
|
||||
for e in &tl.expressions {
|
||||
self.collect_capture_names_expr(e, ref_set, shadow, out);
|
||||
}
|
||||
}
|
||||
Expression::TaggedTemplateExpression(tt) => {
|
||||
self.collect_capture_names_expr(&tt.tag, ref_set, shadow, out);
|
||||
for e in &tt.quasi.expressions {
|
||||
self.collect_capture_names_expr(e, ref_set, shadow, out);
|
||||
}
|
||||
}
|
||||
Expression::ObjectExpression(o) => {
|
||||
for prop in &o.properties {
|
||||
if let oxide_parser::ObjectPropertyKind::ObjectProperty(p) = prop {
|
||||
self.collect_capture_names_expr(&p.value, ref_set, shadow, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
Expression::ChainExpression(c) => self.collect_capture_names_chain(&c.expression, ref_set, shadow, out),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_capture_names_chain(
|
||||
&self, element: &oxide_parser::ChainElement, ref_set: &HashSet<String>, shadow: &HashSet<String>,
|
||||
out: &mut HashSet<String>,
|
||||
) {
|
||||
match element {
|
||||
oxide_parser::ChainElement::StaticMemberExpression(m) => {
|
||||
self.collect_capture_names_expr(&m.object, ref_set, shadow, out);
|
||||
}
|
||||
oxide_parser::ChainElement::ComputedMemberExpression(m) => {
|
||||
self.collect_capture_names_expr(&m.object, ref_set, shadow, out);
|
||||
self.collect_capture_names_expr(&m.expression, ref_set, shadow, out);
|
||||
}
|
||||
oxide_parser::ChainElement::PrivateFieldExpression(m) => {
|
||||
self.collect_capture_names_expr(&m.object, ref_set, shadow, out);
|
||||
}
|
||||
oxide_parser::ChainElement::CallExpression(call) => {
|
||||
self.collect_capture_names_expr(&call.callee, ref_set, shadow, out);
|
||||
for a in &call.arguments {
|
||||
if let Some(e) = a.as_expression() {
|
||||
self.collect_capture_names_expr(e, ref_set, shadow, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
/// 分析本函数:哪些绑定被任意深度嵌套函数捕获 → captured_bindings。
|
||||
pub(crate) fn collect_captured_bindings(&self, stmts: &[Statement], own: &HashSet<String>) -> BTreeMap<String, u8> {
|
||||
let mut names = HashSet::new();
|
||||
for stmt in stmts {
|
||||
self.collect_captured_stmt(stmt, 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()
|
||||
}
|
||||
|
||||
/// 只从嵌套函数节点进入扫描(本函数直接引用不算捕获)。
|
||||
fn collect_captured_stmt(&self, 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(&[]);
|
||||
self.collect_capture_names(body, own, out);
|
||||
}
|
||||
Statement::ExpressionStatement(es) => self.collect_captured_expr(&es.expression, own, out),
|
||||
Statement::ReturnStatement(rs) => {
|
||||
if let Some(a) = &rs.argument {
|
||||
self.collect_captured_expr(a, own, out);
|
||||
}
|
||||
}
|
||||
Statement::VariableDeclaration(vd) => {
|
||||
for d in &vd.declarations {
|
||||
if let Some(init) = &d.init {
|
||||
self.collect_captured_expr(init, own, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::IfStatement(is) => {
|
||||
self.collect_captured_expr(&is.test, own, out);
|
||||
self.collect_captured_stmt(&is.consequent, own, out);
|
||||
if let Some(alt) = &is.alternate {
|
||||
self.collect_captured_stmt(alt, own, out);
|
||||
}
|
||||
}
|
||||
Statement::ForStatement(fs) => {
|
||||
if let Some(init) = &fs.init {
|
||||
if let Some(e) = init.as_expression() {
|
||||
self.collect_captured_expr(e, own, out);
|
||||
}
|
||||
}
|
||||
if let Some(t) = &fs.test {
|
||||
self.collect_captured_expr(t, own, out);
|
||||
}
|
||||
if let Some(u) = &fs.update {
|
||||
self.collect_captured_expr(u, own, out);
|
||||
}
|
||||
self.collect_captured_stmt(&fs.body, own, out);
|
||||
}
|
||||
Statement::WhileStatement(w) => {
|
||||
self.collect_captured_expr(&w.test, own, out);
|
||||
self.collect_captured_stmt(&w.body, own, out);
|
||||
}
|
||||
Statement::DoWhileStatement(d) => {
|
||||
self.collect_captured_stmt(&d.body, own, out);
|
||||
self.collect_captured_expr(&d.test, own, out);
|
||||
}
|
||||
Statement::ForInStatement(fi) => {
|
||||
self.collect_captured_expr(&fi.right, own, out);
|
||||
self.collect_captured_stmt(&fi.body, own, out);
|
||||
}
|
||||
Statement::ForOfStatement(fo) => {
|
||||
self.collect_captured_expr(&fo.right, own, out);
|
||||
self.collect_captured_stmt(&fo.body, own, out);
|
||||
}
|
||||
Statement::BlockStatement(b) => {
|
||||
for s in &b.body {
|
||||
self.collect_captured_stmt(s, own, out);
|
||||
}
|
||||
}
|
||||
Statement::TryStatement(ts) => {
|
||||
for s in &ts.block.body {
|
||||
self.collect_captured_stmt(s, own, out);
|
||||
}
|
||||
if let Some(h) = &ts.handler {
|
||||
for s in &h.body.body {
|
||||
self.collect_captured_stmt(s, own, out);
|
||||
}
|
||||
}
|
||||
if let Some(f) = &ts.finalizer {
|
||||
for s in &f.body {
|
||||
self.collect_captured_stmt(s, own, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::ThrowStatement(ts) => self.collect_captured_expr(&ts.argument, own, out),
|
||||
Statement::SwitchStatement(sw) => {
|
||||
self.collect_captured_expr(&sw.discriminant, own, out);
|
||||
for case in &sw.cases {
|
||||
for s in &case.consequent {
|
||||
self.collect_captured_stmt(s, own, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::LabeledStatement(ls) => self.collect_captured_stmt(&ls.body, own, out),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_captured_expr(&self, 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 = self.collect_fn_param_names(&fe.params);
|
||||
inner.extend(self.collect_own_binding_names(&[], body));
|
||||
self.collect_capture_names_shadowed(body, own, &inner, out);
|
||||
}
|
||||
Expression::ArrowFunctionExpression(ae) => {
|
||||
let mut inner = self.collect_fn_param_names(&ae.params);
|
||||
inner.extend(self.collect_own_binding_names(&[], &ae.body.statements));
|
||||
self.collect_capture_names_shadowed(&ae.body.statements, own, &inner, out);
|
||||
}
|
||||
Expression::CallExpression(ce) => {
|
||||
self.collect_captured_expr(&ce.callee, own, out);
|
||||
for a in &ce.arguments {
|
||||
if let Some(e) = a.as_expression() {
|
||||
self.collect_captured_expr(e, own, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
Expression::BinaryExpression(be) => {
|
||||
self.collect_captured_expr(&be.left, own, out);
|
||||
self.collect_captured_expr(&be.right, own, out);
|
||||
}
|
||||
Expression::UnaryExpression(ue) => self.collect_captured_expr(&ue.argument, own, out),
|
||||
Expression::LogicalExpression(le) => {
|
||||
self.collect_captured_expr(&le.left, own, out);
|
||||
self.collect_captured_expr(&le.right, own, out);
|
||||
}
|
||||
Expression::ConditionalExpression(ce) => {
|
||||
self.collect_captured_expr(&ce.test, own, out);
|
||||
self.collect_captured_expr(&ce.consequent, own, out);
|
||||
self.collect_captured_expr(&ce.alternate, own, out);
|
||||
}
|
||||
Expression::SequenceExpression(se) => {
|
||||
for e in &se.expressions {
|
||||
self.collect_captured_expr(e, own, out);
|
||||
}
|
||||
}
|
||||
Expression::AssignmentExpression(ae) => self.collect_captured_expr(&ae.right, own, out),
|
||||
Expression::ArrayExpression(ae) => {
|
||||
for e in &ae.elements {
|
||||
if let Some(e) = e.as_expression() {
|
||||
self.collect_captured_expr(e, own, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
/// 分析子函数 body:引用父级绑定的名字 → upvalue_captures(enclosing_reg 由父 emit 完成后填充)。
|
||||
/// 分析子函数 body:引用父级被捕获绑定的名字 → upvalue_captures。
|
||||
/// cell_idx 直接取父 captured_bindings 映射(父 emit 前已确定,索引一致);
|
||||
/// enclosing_reg 由父 emit 完成后填充(assemble_ir)。
|
||||
pub(crate) fn collect_upvalue_names(
|
||||
&self, body_stmts: &[Statement], parent_captured: &BTreeMap<String, u8>, sub_own: &HashSet<String>,
|
||||
) -> Vec<UpvalueCapture> {
|
||||
let parent_names: HashSet<String> = parent_captured.keys().cloned().collect();
|
||||
let mut names = HashSet::new();
|
||||
self.collect_capture_names_shadowed(body_stmts, &parent_names, sub_own, &mut names);
|
||||
names
|
||||
.into_iter()
|
||||
.map(|name| {
|
||||
let cell_idx = parent_captured.get(&name).copied().unwrap_or(0);
|
||||
UpvalueCapture {
|
||||
name,
|
||||
enclosing_reg: 0, // assemble_ir 时从父符号表填充
|
||||
cell_idx,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -523,513 +523,6 @@ impl Compiler {
|
||||
// ── 闭包捕获分析(AST 级,时序无关)──
|
||||
|
||||
/// 收集函数参数的绑定名(BindingIdentifier 形态)。
|
||||
fn collect_fn_param_names(&self, params: &oxide_parser::FormalParameters) -> HashSet<String> {
|
||||
let mut names = HashSet::new();
|
||||
for p in ¶ms.items {
|
||||
if let oxide_parser::BindingPattern::BindingIdentifier(bi) = &p.pattern {
|
||||
names.insert(bi.name.to_string());
|
||||
}
|
||||
}
|
||||
names
|
||||
}
|
||||
|
||||
/// 收集当前函数作用域声明的绑定名(参数 + 变量/函数声明,含嵌套 block,不含嵌套函数体)。
|
||||
fn collect_own_binding_names(&self, param_names: &[&str], stmts: &[Statement]) -> HashSet<String> {
|
||||
let mut names = HashSet::new();
|
||||
for p in param_names {
|
||||
names.insert(p.to_string());
|
||||
}
|
||||
self.collect_decl_names_stmt(stmts, &mut names);
|
||||
names
|
||||
}
|
||||
|
||||
fn collect_decl_names_stmt(&self, stmts: &[Statement], out: &mut HashSet<String>) {
|
||||
for stmt in stmts {
|
||||
match stmt {
|
||||
Statement::VariableDeclaration(vd) => {
|
||||
for d in &vd.declarations {
|
||||
if let oxide_parser::BindingPattern::BindingIdentifier(bi) = &d.id {
|
||||
out.insert(bi.name.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::FunctionDeclaration(fd) => {
|
||||
if let Some(id) = &fd.id {
|
||||
out.insert(id.name.to_string());
|
||||
}
|
||||
}
|
||||
Statement::BlockStatement(b) => self.collect_decl_names_stmt(&b.body, out),
|
||||
Statement::IfStatement(is) => {
|
||||
self.collect_decl_names_stmt(std::slice::from_ref(&is.consequent), out);
|
||||
if let Some(alt) = &is.alternate {
|
||||
self.collect_decl_names_stmt(std::slice::from_ref(alt), out);
|
||||
}
|
||||
}
|
||||
Statement::WhileStatement(w) => self.collect_decl_names_stmt(std::slice::from_ref(&w.body), out),
|
||||
Statement::DoWhileStatement(d) => self.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());
|
||||
}
|
||||
}
|
||||
}
|
||||
self.collect_decl_names_stmt(std::slice::from_ref(&f.body), out);
|
||||
}
|
||||
Statement::SwitchStatement(sw) => {
|
||||
for case in &sw.cases {
|
||||
self.collect_decl_names_stmt(&case.consequent, out);
|
||||
}
|
||||
}
|
||||
Statement::TryStatement(ts) => {
|
||||
self.collect_decl_names_stmt(&ts.block.body, out);
|
||||
if let Some(h) = &ts.handler {
|
||||
self.collect_decl_names_stmt(&h.body.body, out);
|
||||
}
|
||||
if let Some(f) = &ts.finalizer {
|
||||
self.collect_decl_names_stmt(&f.body, out);
|
||||
}
|
||||
}
|
||||
Statement::LabeledStatement(ls) => self.collect_decl_names_stmt(std::slice::from_ref(&ls.body), out),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 扫描 stmts 内(含任意深度嵌套函数)对 `ref_set` 的引用,写入 out。
|
||||
/// 递归进入嵌套函数时累加其局部绑定为遮蔽集,避免把内层局部误判为捕获。
|
||||
fn collect_capture_names(&self, stmts: &[Statement], ref_set: &HashSet<String>, out: &mut HashSet<String>) {
|
||||
let shadow = HashSet::new();
|
||||
self.collect_capture_names_shadowed(stmts, ref_set, &shadow, out);
|
||||
}
|
||||
|
||||
fn collect_capture_names_shadowed(
|
||||
&self, stmts: &[Statement], ref_set: &HashSet<String>, shadow: &HashSet<String>, out: &mut HashSet<String>,
|
||||
) {
|
||||
for stmt in stmts {
|
||||
self.collect_capture_names_stmt(stmt, ref_set, shadow, out);
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_capture_names_stmt(
|
||||
&self, stmt: &Statement, ref_set: &HashSet<String>, shadow: &HashSet<String>, out: &mut HashSet<String>,
|
||||
) {
|
||||
match stmt {
|
||||
Statement::ExpressionStatement(es) => self.collect_capture_names_expr(&es.expression, ref_set, shadow, out),
|
||||
Statement::ReturnStatement(rs) => {
|
||||
if let Some(a) = &rs.argument {
|
||||
self.collect_capture_names_expr(a, ref_set, shadow, out);
|
||||
}
|
||||
}
|
||||
Statement::VariableDeclaration(vd) => {
|
||||
for d in &vd.declarations {
|
||||
if let Some(init) = &d.init {
|
||||
self.collect_capture_names_expr(init, ref_set, shadow, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::FunctionDeclaration(fd) => {
|
||||
let body: &[Statement] = fd.body.as_ref().map(|b| &b.statements[..]).unwrap_or(&[]);
|
||||
let mut inner = shadow.clone();
|
||||
inner.extend(self.collect_fn_param_names(&fd.params));
|
||||
inner.extend(self.collect_own_binding_names(&[], body));
|
||||
self.collect_capture_names_shadowed(body, ref_set, &inner, out);
|
||||
}
|
||||
Statement::IfStatement(is) => {
|
||||
self.collect_capture_names_expr(&is.test, ref_set, shadow, out);
|
||||
self.collect_capture_names_stmt(&is.consequent, ref_set, shadow, out);
|
||||
if let Some(alt) = &is.alternate {
|
||||
self.collect_capture_names_stmt(alt, ref_set, shadow, out);
|
||||
}
|
||||
}
|
||||
Statement::ForStatement(fs) => {
|
||||
if let Some(init) = &fs.init {
|
||||
if let Some(e) = init.as_expression() {
|
||||
self.collect_capture_names_expr(e, ref_set, shadow, out);
|
||||
}
|
||||
if let oxide_parser::ForStatementInit::VariableDeclaration(vd) = init {
|
||||
for d in &vd.declarations {
|
||||
if let Some(i) = &d.init {
|
||||
self.collect_capture_names_expr(i, ref_set, shadow, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(t) = &fs.test {
|
||||
self.collect_capture_names_expr(t, ref_set, shadow, out);
|
||||
}
|
||||
if let Some(u) = &fs.update {
|
||||
self.collect_capture_names_expr(u, ref_set, shadow, out);
|
||||
}
|
||||
self.collect_capture_names_stmt(&fs.body, ref_set, shadow, out);
|
||||
}
|
||||
Statement::WhileStatement(w) => {
|
||||
self.collect_capture_names_expr(&w.test, ref_set, shadow, out);
|
||||
self.collect_capture_names_stmt(&w.body, ref_set, shadow, out);
|
||||
}
|
||||
Statement::DoWhileStatement(d) => {
|
||||
self.collect_capture_names_stmt(&d.body, ref_set, shadow, out);
|
||||
self.collect_capture_names_expr(&d.test, ref_set, shadow, out);
|
||||
}
|
||||
Statement::ForInStatement(fi) => {
|
||||
self.collect_capture_names_expr(&fi.right, ref_set, shadow, out);
|
||||
self.collect_capture_names_stmt(&fi.body, ref_set, shadow, out);
|
||||
}
|
||||
Statement::ForOfStatement(fo) => {
|
||||
self.collect_capture_names_expr(&fo.right, ref_set, shadow, out);
|
||||
self.collect_capture_names_stmt(&fo.body, ref_set, shadow, out);
|
||||
}
|
||||
Statement::BlockStatement(b) => self.collect_capture_names_shadowed(&b.body, ref_set, shadow, out),
|
||||
Statement::TryStatement(ts) => {
|
||||
for s in &ts.block.body {
|
||||
self.collect_capture_names_stmt(s, ref_set, shadow, out);
|
||||
}
|
||||
if let Some(h) = &ts.handler {
|
||||
for s in &h.body.body {
|
||||
self.collect_capture_names_stmt(s, ref_set, shadow, out);
|
||||
}
|
||||
}
|
||||
if let Some(f) = &ts.finalizer {
|
||||
for s in &f.body {
|
||||
self.collect_capture_names_stmt(s, ref_set, shadow, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::ThrowStatement(ts) => self.collect_capture_names_expr(&ts.argument, ref_set, shadow, out),
|
||||
Statement::SwitchStatement(sw) => {
|
||||
self.collect_capture_names_expr(&sw.discriminant, ref_set, shadow, out);
|
||||
for case in &sw.cases {
|
||||
for s in &case.consequent {
|
||||
self.collect_capture_names_stmt(s, ref_set, shadow, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::LabeledStatement(ls) => self.collect_capture_names_stmt(&ls.body, ref_set, shadow, out),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_capture_names_expr(
|
||||
&self, expr: &Expression, ref_set: &HashSet<String>, shadow: &HashSet<String>, out: &mut HashSet<String>,
|
||||
) {
|
||||
match expr {
|
||||
Expression::Identifier(id) => {
|
||||
let name = id.name.as_str();
|
||||
if ref_set.contains(name) && !shadow.contains(name) {
|
||||
out.insert(id.name.to_string());
|
||||
}
|
||||
}
|
||||
Expression::AssignmentExpression(ae) => {
|
||||
if let oxide_parser::AssignmentTarget::AssignmentTargetIdentifier(ati) = &ae.left {
|
||||
let name = ati.name.as_str();
|
||||
if ref_set.contains(name) && !shadow.contains(name) {
|
||||
out.insert(ati.name.to_string());
|
||||
}
|
||||
}
|
||||
self.collect_capture_names_expr(&ae.right, ref_set, shadow, out);
|
||||
}
|
||||
Expression::UpdateExpression(ue) => {
|
||||
if let oxide_parser::SimpleAssignmentTarget::AssignmentTargetIdentifier(ati) = &ue.argument {
|
||||
let name = ati.name.as_str();
|
||||
if ref_set.contains(name) && !shadow.contains(name) {
|
||||
out.insert(ati.name.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
Expression::FunctionExpression(fe) => {
|
||||
let body: &[Statement] = fe.body.as_ref().map(|b| &b.statements[..]).unwrap_or(&[]);
|
||||
let mut inner = shadow.clone();
|
||||
inner.extend(self.collect_fn_param_names(&fe.params));
|
||||
inner.extend(self.collect_own_binding_names(&[], body));
|
||||
self.collect_capture_names_shadowed(body, ref_set, &inner, out);
|
||||
}
|
||||
Expression::ArrowFunctionExpression(ae) => {
|
||||
let mut inner = shadow.clone();
|
||||
inner.extend(self.collect_fn_param_names(&ae.params));
|
||||
inner.extend(self.collect_own_binding_names(&[], &ae.body.statements));
|
||||
self.collect_capture_names_shadowed(&ae.body.statements, ref_set, &inner, out);
|
||||
}
|
||||
Expression::BinaryExpression(be) => {
|
||||
self.collect_capture_names_expr(&be.left, ref_set, shadow, out);
|
||||
self.collect_capture_names_expr(&be.right, ref_set, shadow, out);
|
||||
}
|
||||
Expression::UnaryExpression(ue) => self.collect_capture_names_expr(&ue.argument, ref_set, shadow, out),
|
||||
Expression::CallExpression(ce) => {
|
||||
self.collect_capture_names_expr(&ce.callee, ref_set, shadow, out);
|
||||
for a in &ce.arguments {
|
||||
if let Some(e) = a.as_expression() {
|
||||
self.collect_capture_names_expr(e, ref_set, shadow, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
Expression::NewExpression(ne) => {
|
||||
self.collect_capture_names_expr(&ne.callee, ref_set, shadow, out);
|
||||
for a in &ne.arguments {
|
||||
if let Some(e) = a.as_expression() {
|
||||
self.collect_capture_names_expr(e, ref_set, shadow, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
Expression::SequenceExpression(se) => {
|
||||
for e in &se.expressions {
|
||||
self.collect_capture_names_expr(e, ref_set, shadow, out);
|
||||
}
|
||||
}
|
||||
Expression::ConditionalExpression(ce) => {
|
||||
self.collect_capture_names_expr(&ce.test, ref_set, shadow, out);
|
||||
self.collect_capture_names_expr(&ce.consequent, ref_set, shadow, out);
|
||||
self.collect_capture_names_expr(&ce.alternate, ref_set, shadow, out);
|
||||
}
|
||||
Expression::ArrayExpression(ae) => {
|
||||
for e in &ae.elements {
|
||||
if let Some(e) = e.as_expression() {
|
||||
self.collect_capture_names_expr(e, ref_set, shadow, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
Expression::LogicalExpression(le) => {
|
||||
self.collect_capture_names_expr(&le.left, ref_set, shadow, out);
|
||||
self.collect_capture_names_expr(&le.right, ref_set, shadow, out);
|
||||
}
|
||||
Expression::ComputedMemberExpression(m) => {
|
||||
self.collect_capture_names_expr(&m.object, ref_set, shadow, out);
|
||||
self.collect_capture_names_expr(&m.expression, ref_set, shadow, out);
|
||||
}
|
||||
Expression::StaticMemberExpression(m) => self.collect_capture_names_expr(&m.object, ref_set, shadow, out),
|
||||
Expression::PrivateFieldExpression(m) => self.collect_capture_names_expr(&m.object, ref_set, shadow, out),
|
||||
Expression::ParenthesizedExpression(p) => self.collect_capture_names_expr(&p.expression, ref_set, shadow, out),
|
||||
Expression::TemplateLiteral(tl) => {
|
||||
for e in &tl.expressions {
|
||||
self.collect_capture_names_expr(e, ref_set, shadow, out);
|
||||
}
|
||||
}
|
||||
Expression::TaggedTemplateExpression(tt) => {
|
||||
self.collect_capture_names_expr(&tt.tag, ref_set, shadow, out);
|
||||
for e in &tt.quasi.expressions {
|
||||
self.collect_capture_names_expr(e, ref_set, shadow, out);
|
||||
}
|
||||
}
|
||||
Expression::ObjectExpression(o) => {
|
||||
for prop in &o.properties {
|
||||
if let oxide_parser::ObjectPropertyKind::ObjectProperty(p) = prop {
|
||||
self.collect_capture_names_expr(&p.value, ref_set, shadow, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
Expression::ChainExpression(c) => self.collect_capture_names_chain(&c.expression, ref_set, shadow, out),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_capture_names_chain(
|
||||
&self, element: &oxide_parser::ChainElement, ref_set: &HashSet<String>, shadow: &HashSet<String>,
|
||||
out: &mut HashSet<String>,
|
||||
) {
|
||||
match element {
|
||||
oxide_parser::ChainElement::StaticMemberExpression(m) => {
|
||||
self.collect_capture_names_expr(&m.object, ref_set, shadow, out);
|
||||
}
|
||||
oxide_parser::ChainElement::ComputedMemberExpression(m) => {
|
||||
self.collect_capture_names_expr(&m.object, ref_set, shadow, out);
|
||||
self.collect_capture_names_expr(&m.expression, ref_set, shadow, out);
|
||||
}
|
||||
oxide_parser::ChainElement::PrivateFieldExpression(m) => {
|
||||
self.collect_capture_names_expr(&m.object, ref_set, shadow, out);
|
||||
}
|
||||
oxide_parser::ChainElement::CallExpression(call) => {
|
||||
self.collect_capture_names_expr(&call.callee, ref_set, shadow, out);
|
||||
for a in &call.arguments {
|
||||
if let Some(e) = a.as_expression() {
|
||||
self.collect_capture_names_expr(e, ref_set, shadow, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
/// 分析本函数:哪些绑定被任意深度嵌套函数捕获 → captured_bindings。
|
||||
fn collect_captured_bindings(&self, stmts: &[Statement], own: &HashSet<String>) -> BTreeMap<String, u8> {
|
||||
let mut names = HashSet::new();
|
||||
for stmt in stmts {
|
||||
self.collect_captured_stmt(stmt, 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()
|
||||
}
|
||||
|
||||
/// 只从嵌套函数节点进入扫描(本函数直接引用不算捕获)。
|
||||
fn collect_captured_stmt(&self, 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(&[]);
|
||||
self.collect_capture_names(body, own, out);
|
||||
}
|
||||
Statement::ExpressionStatement(es) => self.collect_captured_expr(&es.expression, own, out),
|
||||
Statement::ReturnStatement(rs) => {
|
||||
if let Some(a) = &rs.argument {
|
||||
self.collect_captured_expr(a, own, out);
|
||||
}
|
||||
}
|
||||
Statement::VariableDeclaration(vd) => {
|
||||
for d in &vd.declarations {
|
||||
if let Some(init) = &d.init {
|
||||
self.collect_captured_expr(init, own, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::IfStatement(is) => {
|
||||
self.collect_captured_expr(&is.test, own, out);
|
||||
self.collect_captured_stmt(&is.consequent, own, out);
|
||||
if let Some(alt) = &is.alternate {
|
||||
self.collect_captured_stmt(alt, own, out);
|
||||
}
|
||||
}
|
||||
Statement::ForStatement(fs) => {
|
||||
if let Some(init) = &fs.init {
|
||||
if let Some(e) = init.as_expression() {
|
||||
self.collect_captured_expr(e, own, out);
|
||||
}
|
||||
}
|
||||
if let Some(t) = &fs.test {
|
||||
self.collect_captured_expr(t, own, out);
|
||||
}
|
||||
if let Some(u) = &fs.update {
|
||||
self.collect_captured_expr(u, own, out);
|
||||
}
|
||||
self.collect_captured_stmt(&fs.body, own, out);
|
||||
}
|
||||
Statement::WhileStatement(w) => {
|
||||
self.collect_captured_expr(&w.test, own, out);
|
||||
self.collect_captured_stmt(&w.body, own, out);
|
||||
}
|
||||
Statement::DoWhileStatement(d) => {
|
||||
self.collect_captured_stmt(&d.body, own, out);
|
||||
self.collect_captured_expr(&d.test, own, out);
|
||||
}
|
||||
Statement::ForInStatement(fi) => {
|
||||
self.collect_captured_expr(&fi.right, own, out);
|
||||
self.collect_captured_stmt(&fi.body, own, out);
|
||||
}
|
||||
Statement::ForOfStatement(fo) => {
|
||||
self.collect_captured_expr(&fo.right, own, out);
|
||||
self.collect_captured_stmt(&fo.body, own, out);
|
||||
}
|
||||
Statement::BlockStatement(b) => {
|
||||
for s in &b.body {
|
||||
self.collect_captured_stmt(s, own, out);
|
||||
}
|
||||
}
|
||||
Statement::TryStatement(ts) => {
|
||||
for s in &ts.block.body {
|
||||
self.collect_captured_stmt(s, own, out);
|
||||
}
|
||||
if let Some(h) = &ts.handler {
|
||||
for s in &h.body.body {
|
||||
self.collect_captured_stmt(s, own, out);
|
||||
}
|
||||
}
|
||||
if let Some(f) = &ts.finalizer {
|
||||
for s in &f.body {
|
||||
self.collect_captured_stmt(s, own, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::ThrowStatement(ts) => self.collect_captured_expr(&ts.argument, own, out),
|
||||
Statement::SwitchStatement(sw) => {
|
||||
self.collect_captured_expr(&sw.discriminant, own, out);
|
||||
for case in &sw.cases {
|
||||
for s in &case.consequent {
|
||||
self.collect_captured_stmt(s, own, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::LabeledStatement(ls) => self.collect_captured_stmt(&ls.body, own, out),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_captured_expr(&self, 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 = self.collect_fn_param_names(&fe.params);
|
||||
inner.extend(self.collect_own_binding_names(&[], body));
|
||||
self.collect_capture_names_shadowed(body, own, &inner, out);
|
||||
}
|
||||
Expression::ArrowFunctionExpression(ae) => {
|
||||
let mut inner = self.collect_fn_param_names(&ae.params);
|
||||
inner.extend(self.collect_own_binding_names(&[], &ae.body.statements));
|
||||
self.collect_capture_names_shadowed(&ae.body.statements, own, &inner, out);
|
||||
}
|
||||
Expression::CallExpression(ce) => {
|
||||
self.collect_captured_expr(&ce.callee, own, out);
|
||||
for a in &ce.arguments {
|
||||
if let Some(e) = a.as_expression() {
|
||||
self.collect_captured_expr(e, own, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
Expression::BinaryExpression(be) => {
|
||||
self.collect_captured_expr(&be.left, own, out);
|
||||
self.collect_captured_expr(&be.right, own, out);
|
||||
}
|
||||
Expression::UnaryExpression(ue) => self.collect_captured_expr(&ue.argument, own, out),
|
||||
Expression::LogicalExpression(le) => {
|
||||
self.collect_captured_expr(&le.left, own, out);
|
||||
self.collect_captured_expr(&le.right, own, out);
|
||||
}
|
||||
Expression::ConditionalExpression(ce) => {
|
||||
self.collect_captured_expr(&ce.test, own, out);
|
||||
self.collect_captured_expr(&ce.consequent, own, out);
|
||||
self.collect_captured_expr(&ce.alternate, own, out);
|
||||
}
|
||||
Expression::SequenceExpression(se) => {
|
||||
for e in &se.expressions {
|
||||
self.collect_captured_expr(e, own, out);
|
||||
}
|
||||
}
|
||||
Expression::AssignmentExpression(ae) => self.collect_captured_expr(&ae.right, own, out),
|
||||
Expression::ArrayExpression(ae) => {
|
||||
for e in &ae.elements {
|
||||
if let Some(e) = e.as_expression() {
|
||||
self.collect_captured_expr(e, own, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
/// 分析子函数 body:引用父级绑定的名字 → upvalue_captures(enclosing_reg 由父 emit 完成后填充)。
|
||||
/// 分析子函数 body:引用父级被捕获绑定的名字 → upvalue_captures。
|
||||
/// cell_idx 直接取父 captured_bindings 映射(父 emit 前已确定,索引一致);
|
||||
/// enclosing_reg 由父 emit 完成后填充(assemble_ir)。
|
||||
fn collect_upvalue_names(
|
||||
&self, body_stmts: &[Statement], parent_captured: &BTreeMap<String, u8>, sub_own: &HashSet<String>,
|
||||
) -> Vec<UpvalueCapture> {
|
||||
let parent_names: HashSet<String> = parent_captured.keys().cloned().collect();
|
||||
let mut names = HashSet::new();
|
||||
self.collect_capture_names_shadowed(body_stmts, &parent_names, sub_own, &mut names);
|
||||
names
|
||||
.into_iter()
|
||||
.map(|name| {
|
||||
let cell_idx = parent_captured.get(&name).copied().unwrap_or(0);
|
||||
UpvalueCapture {
|
||||
name,
|
||||
enclosing_reg: 0, // assemble_ir 时从父符号表填充
|
||||
cell_idx,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
|
||||
pub(crate) fn extract_function_parts<'a>(
|
||||
@@ -1104,341 +597,6 @@ impl Compiler {
|
||||
/// `lookup_or_builtin` at first use, which can collide with a temporary
|
||||
/// register already reused by `restore_reg_checkpoint`. Pre-scanning moves
|
||||
/// builtin slot allocation ahead of the temporary register pool.
|
||||
pub(crate) fn pre_register_builtin_references(&self, stmts: &[Statement], ctx: &mut CompileCtx) {
|
||||
for stmt in stmts {
|
||||
self.pre_scan_builtin_stmt(stmt, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
fn pre_scan_builtin_stmt(&self, stmt: &Statement, ctx: &mut CompileCtx) {
|
||||
match stmt {
|
||||
Statement::ExpressionStatement(es) => self.pre_scan_builtin_expr(&es.expression, ctx),
|
||||
Statement::VariableDeclaration(vd) => {
|
||||
for d in &vd.declarations {
|
||||
if let Some(init) = &d.init {
|
||||
self.pre_scan_builtin_expr(init, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::ReturnStatement(rs) => {
|
||||
if let Some(a) = &rs.argument {
|
||||
self.pre_scan_builtin_expr(a, ctx);
|
||||
}
|
||||
}
|
||||
Statement::IfStatement(is) => {
|
||||
self.pre_scan_builtin_expr(&is.test, ctx);
|
||||
self.pre_scan_builtin_stmt(&is.consequent, ctx);
|
||||
if let Some(alt) = &is.alternate {
|
||||
self.pre_scan_builtin_stmt(alt, ctx);
|
||||
}
|
||||
}
|
||||
Statement::WhileStatement(wh) => {
|
||||
self.pre_scan_builtin_expr(&wh.test, ctx);
|
||||
self.pre_scan_builtin_stmt(&wh.body, ctx);
|
||||
}
|
||||
Statement::DoWhileStatement(dw) => {
|
||||
self.pre_scan_builtin_stmt(&dw.body, ctx);
|
||||
self.pre_scan_builtin_expr(&dw.test, ctx);
|
||||
}
|
||||
Statement::ForStatement(fs) => {
|
||||
if let Some(init) = &fs.init {
|
||||
if let Some(e) = init.as_expression() {
|
||||
self.pre_scan_builtin_expr(e, ctx);
|
||||
} else if let oxide_parser::ForStatementInit::VariableDeclaration(decl) = init {
|
||||
for d in &decl.declarations {
|
||||
if let Some(init_expr) = &d.init {
|
||||
self.pre_scan_builtin_expr(init_expr, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(t) = &fs.test {
|
||||
self.pre_scan_builtin_expr(t, ctx);
|
||||
}
|
||||
if let Some(u) = &fs.update {
|
||||
self.pre_scan_builtin_expr(u, ctx);
|
||||
}
|
||||
self.pre_scan_builtin_stmt(&fs.body, ctx);
|
||||
}
|
||||
Statement::ForInStatement(fi) => {
|
||||
self.pre_scan_builtin_expr(&fi.right, ctx);
|
||||
self.pre_scan_builtin_stmt(&fi.body, ctx);
|
||||
}
|
||||
Statement::ForOfStatement(fo) => {
|
||||
self.pre_scan_builtin_expr(&fo.right, ctx);
|
||||
self.pre_scan_builtin_stmt(&fo.body, ctx);
|
||||
}
|
||||
Statement::SwitchStatement(sw) => {
|
||||
self.pre_scan_builtin_expr(&sw.discriminant, ctx);
|
||||
for case in &sw.cases {
|
||||
if let Some(test) = &case.test {
|
||||
self.pre_scan_builtin_expr(test, ctx);
|
||||
}
|
||||
for s in &case.consequent {
|
||||
self.pre_scan_builtin_stmt(s, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::ThrowStatement(ts) => {
|
||||
self.pre_scan_builtin_expr(&ts.argument, ctx);
|
||||
}
|
||||
Statement::TryStatement(ts) => {
|
||||
for s in &ts.block.body {
|
||||
self.pre_scan_builtin_stmt(s, ctx);
|
||||
}
|
||||
if let Some(handler) = &ts.handler {
|
||||
for s in &handler.body.body {
|
||||
self.pre_scan_builtin_stmt(s, ctx);
|
||||
}
|
||||
}
|
||||
if let Some(finalizer) = &ts.finalizer {
|
||||
for s in &finalizer.body {
|
||||
self.pre_scan_builtin_stmt(s, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::BlockStatement(bs) => {
|
||||
for s in &bs.body {
|
||||
self.pre_scan_builtin_stmt(s, ctx);
|
||||
}
|
||||
}
|
||||
Statement::LabeledStatement(ls) => self.pre_scan_builtin_stmt(&ls.body, ctx),
|
||||
Statement::ClassDeclaration(cd) => {
|
||||
if let Some(super_class) = &cd.super_class {
|
||||
self.pre_scan_builtin_expr(super_class, ctx);
|
||||
}
|
||||
}
|
||||
Statement::FunctionDeclaration(_) | Statement::BreakStatement(_) | Statement::ContinueStatement(_) => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn pre_scan_builtin_expr(&self, expr: &Expression, ctx: &mut CompileCtx) {
|
||||
match expr {
|
||||
Expression::Identifier(ident) => {
|
||||
if CompileCtx::is_known_builtin(ident.name.as_str()) {
|
||||
let _ = ctx.lookup_or_builtin(ident.name.as_str());
|
||||
}
|
||||
}
|
||||
Expression::BinaryExpression(bin) => {
|
||||
self.pre_scan_builtin_expr(&bin.left, ctx);
|
||||
self.pre_scan_builtin_expr(&bin.right, ctx);
|
||||
}
|
||||
Expression::UnaryExpression(un) => {
|
||||
self.pre_scan_builtin_expr(&un.argument, ctx);
|
||||
}
|
||||
Expression::CallExpression(call) => {
|
||||
self.pre_scan_builtin_expr(&call.callee, ctx);
|
||||
for arg in &call.arguments {
|
||||
if let Some(e) = arg.as_expression() {
|
||||
self.pre_scan_builtin_expr(e, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
Expression::NewExpression(ne) => {
|
||||
self.pre_scan_builtin_expr(&ne.callee, ctx);
|
||||
for arg in &ne.arguments {
|
||||
if let Some(e) = arg.as_expression() {
|
||||
self.pre_scan_builtin_expr(e, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
Expression::LogicalExpression(log) => {
|
||||
self.pre_scan_builtin_expr(&log.left, ctx);
|
||||
self.pre_scan_builtin_expr(&log.right, ctx);
|
||||
}
|
||||
Expression::ConditionalExpression(cond) => {
|
||||
self.pre_scan_builtin_expr(&cond.test, ctx);
|
||||
self.pre_scan_builtin_expr(&cond.consequent, ctx);
|
||||
self.pre_scan_builtin_expr(&cond.alternate, ctx);
|
||||
}
|
||||
Expression::PrivateInExpression(pin) => {
|
||||
self.pre_scan_builtin_expr(&pin.right, ctx);
|
||||
}
|
||||
Expression::SequenceExpression(seq) => {
|
||||
for e in &seq.expressions {
|
||||
self.pre_scan_builtin_expr(e, ctx);
|
||||
}
|
||||
}
|
||||
Expression::AssignmentExpression(assign) => {
|
||||
if let Some(target) = assign.left.as_simple_assignment_target() {
|
||||
self.pre_scan_builtin_target(target, ctx);
|
||||
}
|
||||
self.pre_scan_builtin_expr(&assign.right, ctx);
|
||||
}
|
||||
Expression::UpdateExpression(update) => {
|
||||
self.pre_scan_builtin_target(&update.argument, ctx);
|
||||
}
|
||||
Expression::TemplateLiteral(tl) => {
|
||||
for e in &tl.expressions {
|
||||
self.pre_scan_builtin_expr(e, ctx);
|
||||
}
|
||||
}
|
||||
Expression::TaggedTemplateExpression(tt) => {
|
||||
self.pre_scan_builtin_expr(&tt.tag, ctx);
|
||||
for e in &tt.quasi.expressions {
|
||||
self.pre_scan_builtin_expr(e, ctx);
|
||||
}
|
||||
}
|
||||
Expression::ObjectExpression(obj) => {
|
||||
for prop in &obj.properties {
|
||||
if let oxide_parser::ObjectPropertyKind::ObjectProperty(p) = prop {
|
||||
if p.computed {
|
||||
self.pre_scan_builtin_expr(p.key.to_expression(), ctx);
|
||||
}
|
||||
self.pre_scan_builtin_expr(&p.value, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
Expression::ArrayExpression(arr) => {
|
||||
for e in &arr.elements {
|
||||
if let Some(e) = e.as_expression() {
|
||||
self.pre_scan_builtin_expr(e, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
Expression::PrivateFieldExpression(member) => {
|
||||
self.pre_scan_builtin_expr(&member.object, ctx);
|
||||
}
|
||||
Expression::StaticMemberExpression(member) => {
|
||||
self.pre_scan_builtin_expr(&member.object, ctx);
|
||||
}
|
||||
Expression::ComputedMemberExpression(member) => {
|
||||
self.pre_scan_builtin_expr(&member.object, ctx);
|
||||
self.pre_scan_builtin_expr(&member.expression, ctx);
|
||||
}
|
||||
Expression::ChainExpression(chain) => {
|
||||
self.pre_scan_builtin_chain(&chain.expression, ctx);
|
||||
}
|
||||
Expression::ParenthesizedExpression(p) => self.pre_scan_builtin_expr(&p.expression, ctx),
|
||||
Expression::ArrowFunctionExpression(_)
|
||||
| Expression::FunctionExpression(_)
|
||||
| Expression::ClassExpression(_) => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn pre_scan_builtin_target(&self, target: &oxide_parser::SimpleAssignmentTarget, ctx: &mut CompileCtx) {
|
||||
match target {
|
||||
oxide_parser::SimpleAssignmentTarget::StaticMemberExpression(member) => {
|
||||
self.pre_scan_builtin_expr(&member.object, ctx);
|
||||
}
|
||||
oxide_parser::SimpleAssignmentTarget::ComputedMemberExpression(member) => {
|
||||
self.pre_scan_builtin_expr(&member.object, ctx);
|
||||
self.pre_scan_builtin_expr(&member.expression, ctx);
|
||||
}
|
||||
oxide_parser::SimpleAssignmentTarget::PrivateFieldExpression(member) => {
|
||||
self.pre_scan_builtin_expr(&member.object, ctx);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn pre_scan_builtin_chain(&self, element: &oxide_parser::ChainElement, ctx: &mut CompileCtx) {
|
||||
match element {
|
||||
oxide_parser::ChainElement::StaticMemberExpression(member) => {
|
||||
self.pre_scan_builtin_expr(&member.object, ctx);
|
||||
}
|
||||
oxide_parser::ChainElement::ComputedMemberExpression(member) => {
|
||||
self.pre_scan_builtin_expr(&member.object, ctx);
|
||||
self.pre_scan_builtin_expr(&member.expression, ctx);
|
||||
}
|
||||
oxide_parser::ChainElement::PrivateFieldExpression(member) => {
|
||||
self.pre_scan_builtin_expr(&member.object, ctx);
|
||||
}
|
||||
oxide_parser::ChainElement::CallExpression(call) => {
|
||||
self.pre_scan_builtin_expr(&call.callee, ctx);
|
||||
for arg in &call.arguments {
|
||||
if let Some(e) = arg.as_expression() {
|
||||
self.pre_scan_builtin_expr(e, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn predeclare_function_declarations(&self, statements: &[Statement], ctx: &mut CompileCtx) {
|
||||
for statement in statements {
|
||||
let Statement::FunctionDeclaration(function) = statement else {
|
||||
continue;
|
||||
};
|
||||
let Some(identifier) = &function.id else {
|
||||
continue;
|
||||
};
|
||||
let reg = ctx.alloc_reg();
|
||||
let _ = ctx.declare_initialized(identifier.name.as_str(), reg, VariableDeclarationKind::Var, false);
|
||||
}
|
||||
}
|
||||
|
||||
/// Pre-declare all `var` bindings in this statement list so hoisted function
|
||||
/// declarations emitted earlier can resolve them. Mirrors the removed count
|
||||
/// pass behavior (see fe8bd86): top-level `var` names must be visible while
|
||||
/// compiling function bodies that close over them.
|
||||
fn predeclare_var_declarations(&self, statements: &[Statement], ctx: &mut CompileCtx) {
|
||||
for statement in statements {
|
||||
match statement {
|
||||
Statement::VariableDeclaration(decl) => {
|
||||
if !matches!(decl.kind, VariableDeclarationKind::Var) {
|
||||
continue;
|
||||
}
|
||||
for d in &decl.declarations {
|
||||
if let oxide_parser::BindingPattern::BindingIdentifier(bi) = &d.id {
|
||||
let reg = ctx.alloc_reg();
|
||||
let _ = ctx.declare_initialized(bi.name.as_str(), reg, VariableDeclarationKind::Var, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::BlockStatement(bs) => self.predeclare_var_declarations(&bs.body, ctx),
|
||||
Statement::IfStatement(is) => {
|
||||
self.predeclare_var_declarations(std::slice::from_ref(&is.consequent), ctx);
|
||||
if let Some(alt) = &is.alternate {
|
||||
self.predeclare_var_declarations(std::slice::from_ref(alt), ctx);
|
||||
}
|
||||
}
|
||||
Statement::WhileStatement(wh) => {
|
||||
self.predeclare_var_declarations(std::slice::from_ref(&wh.body), ctx);
|
||||
}
|
||||
Statement::DoWhileStatement(dw) => {
|
||||
self.predeclare_var_declarations(std::slice::from_ref(&dw.body), ctx);
|
||||
}
|
||||
Statement::ForStatement(fs) => {
|
||||
if let Some(oxide_parser::ForStatementInit::VariableDeclaration(decl)) = &fs.init {
|
||||
if matches!(decl.kind, VariableDeclarationKind::Var) {
|
||||
for d in &decl.declarations {
|
||||
if let oxide_parser::BindingPattern::BindingIdentifier(bi) = &d.id {
|
||||
let reg = ctx.alloc_reg();
|
||||
let _ =
|
||||
ctx.declare_initialized(bi.name.as_str(), reg, VariableDeclarationKind::Var, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
self.predeclare_var_declarations(std::slice::from_ref(&fs.body), ctx);
|
||||
}
|
||||
Statement::SwitchStatement(sw) => {
|
||||
for case in &sw.cases {
|
||||
self.predeclare_var_declarations(&case.consequent, ctx);
|
||||
}
|
||||
}
|
||||
Statement::TryStatement(ts) => {
|
||||
self.predeclare_var_declarations(&ts.block.body, ctx);
|
||||
if let Some(handler) = &ts.handler {
|
||||
self.predeclare_var_declarations(&handler.body.body, ctx);
|
||||
}
|
||||
if let Some(finalizer) = &ts.finalizer {
|
||||
self.predeclare_var_declarations(&finalizer.body, ctx);
|
||||
}
|
||||
}
|
||||
Statement::LabeledStatement(ls) => {
|
||||
self.predeclare_var_declarations(std::slice::from_ref(&ls.body), ctx);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn compile_function_body_with_field_hooks<'a, E>(
|
||||
&self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx,
|
||||
@@ -1501,35 +659,7 @@ impl Compiler {
|
||||
// same register offset (params go after builtin slots).
|
||||
ctx.reset_regs();
|
||||
|
||||
// Function body scope - params and local vars
|
||||
ctx.push_scope_with_kind(ScopeKind::FunctionScope);
|
||||
|
||||
let param_base = ctx.next_reg;
|
||||
|
||||
// Emit parameters and destructuring prologue.
|
||||
for spec in param_specs {
|
||||
let name = spec.register_name();
|
||||
let reg = ctx.alloc_reg();
|
||||
ctx.declare_initialized(name, reg, VariableDeclarationKind::Var, false)?;
|
||||
}
|
||||
|
||||
for spec in param_specs {
|
||||
if let ParamSpec::Pattern { synthetic_name, pattern } = spec {
|
||||
let src_reg = ctx.lookup(synthetic_name)?;
|
||||
self.emit_binding_pattern(pattern, src_reg, VariableDeclarationKind::Var, false, &mut ctx)?;
|
||||
}
|
||||
}
|
||||
|
||||
// 闭包捕获分析(AST 级,emit 前确定,时序无关)
|
||||
let param_names: Vec<&str> = param_specs.iter().map(|s| s.register_name()).collect();
|
||||
ctx.own_bindings = self.collect_own_binding_names(¶m_names, body_stmts);
|
||||
ctx.captured_bindings = self.collect_captured_bindings(body_stmts, &ctx.own_bindings);
|
||||
|
||||
// Free variable analysis for upvalue capture (Ordinary + Arrow functions only)
|
||||
if matches!(body_context, FunctionBodyContext::Ordinary | FunctionBodyContext::Arrow) {
|
||||
ctx.current_upvalue_captures =
|
||||
self.collect_upvalue_names(body_stmts, &parent_ctx.captured_bindings, &ctx.own_bindings);
|
||||
}
|
||||
let param_base = self.emit_params_prologue(param_specs, body_stmts, parent_ctx, &mut ctx, body_context)?;
|
||||
|
||||
self.predeclare_function_declarations(body_stmts, &mut ctx);
|
||||
|
||||
@@ -1564,25 +694,8 @@ impl Compiler {
|
||||
}
|
||||
}
|
||||
|
||||
// Emit body statements.
|
||||
// First sub-pass: emit function declarations (hoisting + marks parent captures)
|
||||
let mut last_result_reg = None;
|
||||
for stmt in body_stmts {
|
||||
if matches!(stmt, Statement::FunctionDeclaration(_)) {
|
||||
if let Some(reg) = self.emit_statement(stmt, &mut ctx)? {
|
||||
last_result_reg = Some(reg);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Second sub-pass: emit all other statements
|
||||
for stmt in body_stmts {
|
||||
if matches!(stmt, Statement::FunctionDeclaration(_)) {
|
||||
continue;
|
||||
}
|
||||
if let Some(reg) = self.emit_statement(stmt, &mut ctx)? {
|
||||
last_result_reg = Some(reg);
|
||||
}
|
||||
}
|
||||
// Emit body statements(先函数声明 hoisting,再其余)。
|
||||
let last_result_reg = self.emit_body_stmts(body_stmts, &mut ctx)?;
|
||||
|
||||
// Emit implicit RETURN: expression body returns the last expression,
|
||||
// statement body returns undefined.
|
||||
@@ -1612,6 +725,63 @@ impl Compiler {
|
||||
Ok(ir)
|
||||
}
|
||||
|
||||
/// 参数 prologue:函数作用域 + 参数声明/解构 + 闭包捕获与 upvalue 分析。返回 param_base。
|
||||
fn emit_params_prologue<'a>(
|
||||
&self, param_specs: &[ParamSpec<'a>], body_stmts: &[Statement<'a>], parent_ctx: &CompileCtx,
|
||||
ctx: &mut CompileCtx, body_context: FunctionBodyContext,
|
||||
) -> Result<u8, String> {
|
||||
ctx.push_scope_with_kind(ScopeKind::FunctionScope);
|
||||
let param_base = ctx.next_reg;
|
||||
|
||||
// Emit parameters and destructuring prologue.
|
||||
for spec in param_specs {
|
||||
let name = spec.register_name();
|
||||
let reg = ctx.alloc_reg();
|
||||
ctx.declare_initialized(name, reg, VariableDeclarationKind::Var, false)?;
|
||||
}
|
||||
|
||||
for spec in param_specs {
|
||||
if let ParamSpec::Pattern { synthetic_name, pattern } = spec {
|
||||
let src_reg = ctx.lookup(synthetic_name)?;
|
||||
self.emit_binding_pattern(pattern, src_reg, VariableDeclarationKind::Var, false, ctx)?;
|
||||
}
|
||||
}
|
||||
|
||||
// 闭包捕获分析(AST 级,emit 前确定,时序无关)
|
||||
let param_names: Vec<&str> = param_specs.iter().map(|s| s.register_name()).collect();
|
||||
ctx.own_bindings = self.collect_own_binding_names(¶m_names, body_stmts);
|
||||
ctx.captured_bindings = self.collect_captured_bindings(body_stmts, &ctx.own_bindings);
|
||||
|
||||
// Free variable analysis for upvalue capture (Ordinary + Arrow functions only)
|
||||
if matches!(body_context, FunctionBodyContext::Ordinary | FunctionBodyContext::Arrow) {
|
||||
ctx.current_upvalue_captures =
|
||||
self.collect_upvalue_names(body_stmts, &parent_ctx.captured_bindings, &ctx.own_bindings);
|
||||
}
|
||||
|
||||
Ok(param_base)
|
||||
}
|
||||
|
||||
/// 双 sub-pass emit body:先函数声明(hoisting),再其余语句。返回最后结果寄存器。
|
||||
fn emit_body_stmts(&self, body_stmts: &[Statement], ctx: &mut CompileCtx) -> Result<Option<u8>, String> {
|
||||
let mut last_result_reg = None;
|
||||
for stmt in body_stmts {
|
||||
if matches!(stmt, Statement::FunctionDeclaration(_)) {
|
||||
if let Some(reg) = self.emit_statement(stmt, ctx)? {
|
||||
last_result_reg = Some(reg);
|
||||
}
|
||||
}
|
||||
}
|
||||
for stmt in body_stmts {
|
||||
if matches!(stmt, Statement::FunctionDeclaration(_)) {
|
||||
continue;
|
||||
}
|
||||
if let Some(reg) = self.emit_statement(stmt, ctx)? {
|
||||
last_result_reg = Some(reg);
|
||||
}
|
||||
}
|
||||
Ok(last_result_reg)
|
||||
}
|
||||
|
||||
pub(crate) fn emit_statement(&self, stmt: &Statement, ctx: &mut CompileCtx) -> Result<Option<u8>, String> {
|
||||
match stmt {
|
||||
Statement::ExpressionStatement(_) | Statement::ReturnStatement(_) | Statement::EmptyStatement(_) => {
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
#![doc = "OxideJS - AST to bytecode compiler"]
|
||||
|
||||
pub mod class;
|
||||
pub mod closure;
|
||||
pub mod compiler;
|
||||
pub mod compiler_log;
|
||||
pub mod emit_ctx;
|
||||
pub mod expr;
|
||||
pub mod hash;
|
||||
pub mod ir;
|
||||
pub mod prepass;
|
||||
pub mod shared;
|
||||
pub mod stmt;
|
||||
pub mod symbol_table;
|
||||
|
||||
@@ -0,0 +1,343 @@
|
||||
use crate::compiler::{CompileCtx, Compiler};
|
||||
use oxide_parser::{Expression, Statement, VariableDeclarationKind};
|
||||
|
||||
impl Compiler {
|
||||
|
||||
/// builtin slot allocation ahead of the temporary register pool.
|
||||
pub(crate) fn pre_register_builtin_references(&self, stmts: &[Statement], ctx: &mut CompileCtx) {
|
||||
for stmt in stmts {
|
||||
self.pre_scan_builtin_stmt(stmt, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
fn pre_scan_builtin_stmt(&self, stmt: &Statement, ctx: &mut CompileCtx) {
|
||||
match stmt {
|
||||
Statement::ExpressionStatement(es) => self.pre_scan_builtin_expr(&es.expression, ctx),
|
||||
Statement::VariableDeclaration(vd) => {
|
||||
for d in &vd.declarations {
|
||||
if let Some(init) = &d.init {
|
||||
self.pre_scan_builtin_expr(init, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::ReturnStatement(rs) => {
|
||||
if let Some(a) = &rs.argument {
|
||||
self.pre_scan_builtin_expr(a, ctx);
|
||||
}
|
||||
}
|
||||
Statement::IfStatement(is) => {
|
||||
self.pre_scan_builtin_expr(&is.test, ctx);
|
||||
self.pre_scan_builtin_stmt(&is.consequent, ctx);
|
||||
if let Some(alt) = &is.alternate {
|
||||
self.pre_scan_builtin_stmt(alt, ctx);
|
||||
}
|
||||
}
|
||||
Statement::WhileStatement(wh) => {
|
||||
self.pre_scan_builtin_expr(&wh.test, ctx);
|
||||
self.pre_scan_builtin_stmt(&wh.body, ctx);
|
||||
}
|
||||
Statement::DoWhileStatement(dw) => {
|
||||
self.pre_scan_builtin_stmt(&dw.body, ctx);
|
||||
self.pre_scan_builtin_expr(&dw.test, ctx);
|
||||
}
|
||||
Statement::ForStatement(fs) => {
|
||||
if let Some(init) = &fs.init {
|
||||
if let Some(e) = init.as_expression() {
|
||||
self.pre_scan_builtin_expr(e, ctx);
|
||||
} else if let oxide_parser::ForStatementInit::VariableDeclaration(decl) = init {
|
||||
for d in &decl.declarations {
|
||||
if let Some(init_expr) = &d.init {
|
||||
self.pre_scan_builtin_expr(init_expr, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(t) = &fs.test {
|
||||
self.pre_scan_builtin_expr(t, ctx);
|
||||
}
|
||||
if let Some(u) = &fs.update {
|
||||
self.pre_scan_builtin_expr(u, ctx);
|
||||
}
|
||||
self.pre_scan_builtin_stmt(&fs.body, ctx);
|
||||
}
|
||||
Statement::ForInStatement(fi) => {
|
||||
self.pre_scan_builtin_expr(&fi.right, ctx);
|
||||
self.pre_scan_builtin_stmt(&fi.body, ctx);
|
||||
}
|
||||
Statement::ForOfStatement(fo) => {
|
||||
self.pre_scan_builtin_expr(&fo.right, ctx);
|
||||
self.pre_scan_builtin_stmt(&fo.body, ctx);
|
||||
}
|
||||
Statement::SwitchStatement(sw) => {
|
||||
self.pre_scan_builtin_expr(&sw.discriminant, ctx);
|
||||
for case in &sw.cases {
|
||||
if let Some(test) = &case.test {
|
||||
self.pre_scan_builtin_expr(test, ctx);
|
||||
}
|
||||
for s in &case.consequent {
|
||||
self.pre_scan_builtin_stmt(s, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::ThrowStatement(ts) => {
|
||||
self.pre_scan_builtin_expr(&ts.argument, ctx);
|
||||
}
|
||||
Statement::TryStatement(ts) => {
|
||||
for s in &ts.block.body {
|
||||
self.pre_scan_builtin_stmt(s, ctx);
|
||||
}
|
||||
if let Some(handler) = &ts.handler {
|
||||
for s in &handler.body.body {
|
||||
self.pre_scan_builtin_stmt(s, ctx);
|
||||
}
|
||||
}
|
||||
if let Some(finalizer) = &ts.finalizer {
|
||||
for s in &finalizer.body {
|
||||
self.pre_scan_builtin_stmt(s, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::BlockStatement(bs) => {
|
||||
for s in &bs.body {
|
||||
self.pre_scan_builtin_stmt(s, ctx);
|
||||
}
|
||||
}
|
||||
Statement::LabeledStatement(ls) => self.pre_scan_builtin_stmt(&ls.body, ctx),
|
||||
Statement::ClassDeclaration(cd) => {
|
||||
if let Some(super_class) = &cd.super_class {
|
||||
self.pre_scan_builtin_expr(super_class, ctx);
|
||||
}
|
||||
}
|
||||
Statement::FunctionDeclaration(_) | Statement::BreakStatement(_) | Statement::ContinueStatement(_) => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn pre_scan_builtin_expr(&self, expr: &Expression, ctx: &mut CompileCtx) {
|
||||
match expr {
|
||||
Expression::Identifier(ident) => {
|
||||
if CompileCtx::is_known_builtin(ident.name.as_str()) {
|
||||
let _ = ctx.lookup_or_builtin(ident.name.as_str());
|
||||
}
|
||||
}
|
||||
Expression::BinaryExpression(bin) => {
|
||||
self.pre_scan_builtin_expr(&bin.left, ctx);
|
||||
self.pre_scan_builtin_expr(&bin.right, ctx);
|
||||
}
|
||||
Expression::UnaryExpression(un) => {
|
||||
self.pre_scan_builtin_expr(&un.argument, ctx);
|
||||
}
|
||||
Expression::CallExpression(call) => {
|
||||
self.pre_scan_builtin_expr(&call.callee, ctx);
|
||||
for arg in &call.arguments {
|
||||
if let Some(e) = arg.as_expression() {
|
||||
self.pre_scan_builtin_expr(e, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
Expression::NewExpression(ne) => {
|
||||
self.pre_scan_builtin_expr(&ne.callee, ctx);
|
||||
for arg in &ne.arguments {
|
||||
if let Some(e) = arg.as_expression() {
|
||||
self.pre_scan_builtin_expr(e, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
Expression::LogicalExpression(log) => {
|
||||
self.pre_scan_builtin_expr(&log.left, ctx);
|
||||
self.pre_scan_builtin_expr(&log.right, ctx);
|
||||
}
|
||||
Expression::ConditionalExpression(cond) => {
|
||||
self.pre_scan_builtin_expr(&cond.test, ctx);
|
||||
self.pre_scan_builtin_expr(&cond.consequent, ctx);
|
||||
self.pre_scan_builtin_expr(&cond.alternate, ctx);
|
||||
}
|
||||
Expression::PrivateInExpression(pin) => {
|
||||
self.pre_scan_builtin_expr(&pin.right, ctx);
|
||||
}
|
||||
Expression::SequenceExpression(seq) => {
|
||||
for e in &seq.expressions {
|
||||
self.pre_scan_builtin_expr(e, ctx);
|
||||
}
|
||||
}
|
||||
Expression::AssignmentExpression(assign) => {
|
||||
if let Some(target) = assign.left.as_simple_assignment_target() {
|
||||
self.pre_scan_builtin_target(target, ctx);
|
||||
}
|
||||
self.pre_scan_builtin_expr(&assign.right, ctx);
|
||||
}
|
||||
Expression::UpdateExpression(update) => {
|
||||
self.pre_scan_builtin_target(&update.argument, ctx);
|
||||
}
|
||||
Expression::TemplateLiteral(tl) => {
|
||||
for e in &tl.expressions {
|
||||
self.pre_scan_builtin_expr(e, ctx);
|
||||
}
|
||||
}
|
||||
Expression::TaggedTemplateExpression(tt) => {
|
||||
self.pre_scan_builtin_expr(&tt.tag, ctx);
|
||||
for e in &tt.quasi.expressions {
|
||||
self.pre_scan_builtin_expr(e, ctx);
|
||||
}
|
||||
}
|
||||
Expression::ObjectExpression(obj) => {
|
||||
for prop in &obj.properties {
|
||||
if let oxide_parser::ObjectPropertyKind::ObjectProperty(p) = prop {
|
||||
if p.computed {
|
||||
self.pre_scan_builtin_expr(p.key.to_expression(), ctx);
|
||||
}
|
||||
self.pre_scan_builtin_expr(&p.value, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
Expression::ArrayExpression(arr) => {
|
||||
for e in &arr.elements {
|
||||
if let Some(e) = e.as_expression() {
|
||||
self.pre_scan_builtin_expr(e, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
Expression::PrivateFieldExpression(member) => {
|
||||
self.pre_scan_builtin_expr(&member.object, ctx);
|
||||
}
|
||||
Expression::StaticMemberExpression(member) => {
|
||||
self.pre_scan_builtin_expr(&member.object, ctx);
|
||||
}
|
||||
Expression::ComputedMemberExpression(member) => {
|
||||
self.pre_scan_builtin_expr(&member.object, ctx);
|
||||
self.pre_scan_builtin_expr(&member.expression, ctx);
|
||||
}
|
||||
Expression::ChainExpression(chain) => {
|
||||
self.pre_scan_builtin_chain(&chain.expression, ctx);
|
||||
}
|
||||
Expression::ParenthesizedExpression(p) => self.pre_scan_builtin_expr(&p.expression, ctx),
|
||||
Expression::ArrowFunctionExpression(_)
|
||||
| Expression::FunctionExpression(_)
|
||||
| Expression::ClassExpression(_) => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn pre_scan_builtin_target(&self, target: &oxide_parser::SimpleAssignmentTarget, ctx: &mut CompileCtx) {
|
||||
match target {
|
||||
oxide_parser::SimpleAssignmentTarget::StaticMemberExpression(member) => {
|
||||
self.pre_scan_builtin_expr(&member.object, ctx);
|
||||
}
|
||||
oxide_parser::SimpleAssignmentTarget::ComputedMemberExpression(member) => {
|
||||
self.pre_scan_builtin_expr(&member.object, ctx);
|
||||
self.pre_scan_builtin_expr(&member.expression, ctx);
|
||||
}
|
||||
oxide_parser::SimpleAssignmentTarget::PrivateFieldExpression(member) => {
|
||||
self.pre_scan_builtin_expr(&member.object, ctx);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn pre_scan_builtin_chain(&self, element: &oxide_parser::ChainElement, ctx: &mut CompileCtx) {
|
||||
match element {
|
||||
oxide_parser::ChainElement::StaticMemberExpression(member) => {
|
||||
self.pre_scan_builtin_expr(&member.object, ctx);
|
||||
}
|
||||
oxide_parser::ChainElement::ComputedMemberExpression(member) => {
|
||||
self.pre_scan_builtin_expr(&member.object, ctx);
|
||||
self.pre_scan_builtin_expr(&member.expression, ctx);
|
||||
}
|
||||
oxide_parser::ChainElement::PrivateFieldExpression(member) => {
|
||||
self.pre_scan_builtin_expr(&member.object, ctx);
|
||||
}
|
||||
oxide_parser::ChainElement::CallExpression(call) => {
|
||||
self.pre_scan_builtin_expr(&call.callee, ctx);
|
||||
for arg in &call.arguments {
|
||||
if let Some(e) = arg.as_expression() {
|
||||
self.pre_scan_builtin_expr(e, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub(crate) fn predeclare_function_declarations(&self, statements: &[Statement], ctx: &mut CompileCtx) {
|
||||
for statement in statements {
|
||||
let Statement::FunctionDeclaration(function) = statement else {
|
||||
continue;
|
||||
};
|
||||
let Some(identifier) = &function.id else {
|
||||
continue;
|
||||
};
|
||||
let reg = ctx.alloc_reg();
|
||||
let _ = ctx.declare_initialized(identifier.name.as_str(), reg, VariableDeclarationKind::Var, false);
|
||||
}
|
||||
}
|
||||
|
||||
/// Pre-declare all `var` bindings in this statement list so hoisted function
|
||||
/// declarations emitted earlier can resolve them. Mirrors the removed count
|
||||
/// pass behavior (see fe8bd86): top-level `var` names must be visible while
|
||||
/// compiling function bodies that close over them.
|
||||
pub(crate) fn predeclare_var_declarations(&self, statements: &[Statement], ctx: &mut CompileCtx) {
|
||||
for statement in statements {
|
||||
match statement {
|
||||
Statement::VariableDeclaration(decl) => {
|
||||
if !matches!(decl.kind, VariableDeclarationKind::Var) {
|
||||
continue;
|
||||
}
|
||||
for d in &decl.declarations {
|
||||
if let oxide_parser::BindingPattern::BindingIdentifier(bi) = &d.id {
|
||||
let reg = ctx.alloc_reg();
|
||||
let _ = ctx.declare_initialized(bi.name.as_str(), reg, VariableDeclarationKind::Var, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::BlockStatement(bs) => self.predeclare_var_declarations(&bs.body, ctx),
|
||||
Statement::IfStatement(is) => {
|
||||
self.predeclare_var_declarations(std::slice::from_ref(&is.consequent), ctx);
|
||||
if let Some(alt) = &is.alternate {
|
||||
self.predeclare_var_declarations(std::slice::from_ref(alt), ctx);
|
||||
}
|
||||
}
|
||||
Statement::WhileStatement(wh) => {
|
||||
self.predeclare_var_declarations(std::slice::from_ref(&wh.body), ctx);
|
||||
}
|
||||
Statement::DoWhileStatement(dw) => {
|
||||
self.predeclare_var_declarations(std::slice::from_ref(&dw.body), ctx);
|
||||
}
|
||||
Statement::ForStatement(fs) => {
|
||||
if let Some(oxide_parser::ForStatementInit::VariableDeclaration(decl)) = &fs.init {
|
||||
if matches!(decl.kind, VariableDeclarationKind::Var) {
|
||||
for d in &decl.declarations {
|
||||
if let oxide_parser::BindingPattern::BindingIdentifier(bi) = &d.id {
|
||||
let reg = ctx.alloc_reg();
|
||||
let _ =
|
||||
ctx.declare_initialized(bi.name.as_str(), reg, VariableDeclarationKind::Var, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
self.predeclare_var_declarations(std::slice::from_ref(&fs.body), ctx);
|
||||
}
|
||||
Statement::SwitchStatement(sw) => {
|
||||
for case in &sw.cases {
|
||||
self.predeclare_var_declarations(&case.consequent, ctx);
|
||||
}
|
||||
}
|
||||
Statement::TryStatement(ts) => {
|
||||
self.predeclare_var_declarations(&ts.block.body, ctx);
|
||||
if let Some(handler) = &ts.handler {
|
||||
self.predeclare_var_declarations(&handler.body.body, ctx);
|
||||
}
|
||||
if let Some(finalizer) = &ts.finalizer {
|
||||
self.predeclare_var_declarations(&finalizer.body, ctx);
|
||||
}
|
||||
}
|
||||
Statement::LabeledStatement(ls) => {
|
||||
self.predeclare_var_declarations(std::slice::from_ref(&ls.body), ctx);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user