Files
OxideJS-New/crates/oxide_emit/src/prepass.rs
T

351 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 槽位。
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 {
self.pre_scan_builtin_arg(arg, ctx);
}
}
Expression::NewExpression(ne) => {
self.pre_scan_builtin_expr(&ne.callee, ctx);
for arg in &ne.arguments {
self.pre_scan_builtin_arg(arg, 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 {
self.pre_scan_builtin_arg(arg, ctx);
}
}
_ => {}
}
}
/// 遍历调用实参:spread 内部表达式也纳入 builtin 预扫描。
fn pre_scan_builtin_arg(&self, arg: &oxide_parser::Argument, ctx: &mut CompileCtx) {
if let Some(e) = arg.as_expression() {
self.pre_scan_builtin_expr(e, ctx);
} else if let oxide_parser::Argument::SpreadElement(sp) = arg {
self.pre_scan_builtin_expr(&sp.argument, 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);
}
}
/// 预声明语句列表中的全部 `var` 绑定,使先发的提升函数声明能解析它们。
/// 顶层 `var` 名在编译闭包捕获它的函数体时必须可见。
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);
}
_ => {}
}
}
}
}