This repository has been archived on 2026-09-15. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
OxideJS/crates/oxide_emit/src/prepass.rs
T
2026-08-05 21:46:47 +08:00

349 lines
15 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! emit 前置 pass:builtin 引用预扫描 + 声明预登记。
//!
//! 在生成临时寄存器前遍历 AST,把内置全局标识符预先登记到固定寄存器槽
//! (builtin_reg_map),避免与临时寄存器池冲突;同时预声明函数/var 声明,
//! 支持提升语义。
use crate::{CompileCtx, Emitter};
use oxide_parser::{Expression, Statement, VariableDeclarationKind};
impl Emitter {
/// 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);
}
_ => {}
}
}
}
}