refactor(compiler): 拆分 oxide_emit 为独立 emit pass crate(依赖倒置)
This commit is contained in:
@@ -0,0 +1,342 @@
|
||||
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);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user