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

413 lines
21 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,声明预登记:函数/var 声明提升预声明、块级函数声明按 ES2015
//! 块绑定预声明、let/const/class 建 TDZ 占位;顶层 lexical 声明撞受限全局名
//! 在声明实例化期拒绝(global_lexical 门控,门控源居 emit_program 调用点)。
use super::check_restricted_global_lexical;
use crate::{CompileCtx, Emitter};
use oxide_parser::{BindingPattern, Declaration, ExportDefaultDeclarationKind, Statement, VariableDeclarationKind};
impl Emitter {
pub(crate) fn predeclare_function_declarations(&self, statements: &[Statement], ctx: &mut CompileCtx) {
for statement in statements {
let function = match statement {
Statement::FunctionDeclaration(f) => f,
Statement::ExportNamedDeclaration(exp) => match &exp.declaration {
Some(Declaration::FunctionDeclaration(f)) => f,
_ => continue,
},
// export default function foo(){}:foo 绑定由 lexical predeclare 以
// Const 预声明(emit 侧 emit_bind_target(Const) 消费预登记槽)。
_ => 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);
}
}
/// 预声明函数体直接子级中标签链直接包裹的函数声明名(Annex B.3.2 Labelled
/// Function Declarations):sloppy 下标签不改变执行流,该声明的名与直接子
/// 函数声明一样是函数作用域 `var` 绑定,须在入口物化闭包前完成预登记。
///
/// # 边界与前提
/// - 仅扫描直接子语句(标签链展开后须是函数声明);标签包块等其它形归块面
/// 块级函数预声明路径。
/// - 与块级函数名收集路径可能对同名重复建绑定:`declare_initialized` 命中
/// 已存在绑定时只补初始化标志,不改变既有寄存器分配,语义幂等。
pub(crate) fn predeclare_labeled_function_declarations(&self, statements: &[Statement], ctx: &mut CompileCtx) {
for statement in statements {
let Some(function) = Self::labeled_function_decl(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` 名:仅顶层(全局作用域)的内置名落内置镜像槽(预载全局
/// 属性值的固定寄存器槽,本轮求值开始时预载),使 GlobalDeclarationInstantiation
/// (脚本顶层声明实例化)序言与声明点同步都用入口原值,而非程序求值前
/// define-if-absent 序列新建的 undefined 槽,现存值(NaN 等)不被抹;函数体内
/// 内置名仍是局部 var 遮蔽(新建槽,不命中只读内置拦截);其余名新建 var 槽。
pub(crate) fn predeclare_var_name(&self, name: &str, ctx: &mut CompileCtx) {
if ctx.is_global_scope && CompileCtx::is_known_builtin(name) {
let _ = ctx.lookup_or_builtin(name);
} else {
let reg = ctx.alloc_reg();
let _ = ctx.declare_initialized(name, 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 {
self.predeclare_var_name(bi.name.as_str(), ctx);
}
}
}
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 {
self.predeclare_var_name(bi.name.as_str(), ctx);
}
}
}
}
self.predeclare_var_declarations(std::slice::from_ref(&fs.body), ctx);
}
Statement::ForInStatement(fi) => {
// var 头名提升到函数/全局作用域(与 For 臂同规则),先于提升
// 函数声明发射预声明,使函数体按既有 var 绑定解析头名;
// let/const 头是迭代级绑定,不入提升面。
if let oxide_parser::ForStatementLeft::VariableDeclaration(decl) = &fi.left {
if matches!(decl.kind, VariableDeclarationKind::Var) {
for d in &decl.declarations {
if let oxide_parser::BindingPattern::BindingIdentifier(bi) = &d.id {
self.predeclare_var_name(bi.name.as_str(), ctx);
}
}
}
}
self.predeclare_var_declarations(std::slice::from_ref(&fi.body), ctx);
}
Statement::ForOfStatement(fo) => {
if let oxide_parser::ForStatementLeft::VariableDeclaration(decl) = &fo.left {
if matches!(decl.kind, VariableDeclarationKind::Var) {
for d in &decl.declarations {
if let oxide_parser::BindingPattern::BindingIdentifier(bi) = &d.id {
self.predeclare_var_name(bi.name.as_str(), ctx);
}
}
}
}
self.predeclare_var_declarations(std::slice::from_ref(&fo.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);
}
Statement::WithStatement(ws) => {
self.predeclare_var_declarations(std::slice::from_ref(&ws.body), ctx);
}
Statement::ExportNamedDeclaration(exp) => {
if let Some(Declaration::VariableDeclaration(decl)) = &exp.declaration {
if !matches!(decl.kind, VariableDeclarationKind::Var) {
continue;
}
for d in &decl.declarations {
if let oxide_parser::BindingPattern::BindingIdentifier(bi) = &d.id {
self.predeclare_var_name(bi.name.as_str(), ctx);
}
}
}
}
_ => {}
}
}
}
/// 预声明当前块直接子树中的函数声明(ES2015 块级绑定,kind=Let 落当前块),
/// 使块内声明点之前的引用在编译期可见。递归进入嵌套块时压/弹作用域,
/// 与 emit 阶段嵌套块 push_scope 的时机对齐。
///
/// # 边界与前提
/// - 只处理块内函数声明;switch 不推 scope(其 case 内函数声明随 switch
/// 作用域修复一并处理);export 声明不可能出现在块内。
/// - 与 lexical 预声明的顺序:本函数在前,`{ let g; function g(){} }` 时
/// lexical 的 `declare_predeclared` 命中已存在的函数绑定自然报重复声明错,
/// 避免函数预声明被 lexical 占位静默覆盖而破坏 let 的 TDZ。
/// - var 与函数同名(`{ var g; function g(){} }`):var 落函数作用域、
/// 函数落当前块,不同 scope 互不冲突。
pub(crate) fn predeclare_block_function_declarations(&self, statements: &[Statement], ctx: &mut CompileCtx) {
for statement in statements {
match statement {
Statement::FunctionDeclaration(f) => {
let Some(identifier) = &f.id else {
continue;
};
let reg = ctx.alloc_reg();
let _ = ctx.declare_initialized(identifier.name.as_str(), reg, VariableDeclarationKind::Let, false);
}
Statement::BlockStatement(bs) => {
ctx.push_scope();
self.predeclare_block_function_declarations(&bs.body, ctx);
ctx.pop_scope();
}
Statement::IfStatement(is) => {
self.predeclare_block_function_declarations(std::slice::from_ref(&is.consequent), ctx);
if let Some(alt) = &is.alternate {
self.predeclare_block_function_declarations(std::slice::from_ref(alt), ctx);
}
}
Statement::WhileStatement(wh) => {
self.predeclare_block_function_declarations(std::slice::from_ref(&wh.body), ctx);
}
Statement::DoWhileStatement(dw) => {
self.predeclare_block_function_declarations(std::slice::from_ref(&dw.body), ctx);
}
Statement::ForStatement(fs) => {
// 循环推独立作用域(头声明所在),函数声明落该作用域与 emit 对齐。
ctx.push_scope();
self.predeclare_block_function_declarations(std::slice::from_ref(&fs.body), ctx);
ctx.pop_scope();
}
Statement::ForInStatement(fi) => {
ctx.push_scope();
self.predeclare_block_function_declarations(std::slice::from_ref(&fi.body), ctx);
ctx.pop_scope();
}
Statement::ForOfStatement(fo) => {
ctx.push_scope();
self.predeclare_block_function_declarations(std::slice::from_ref(&fo.body), ctx);
ctx.pop_scope();
}
Statement::TryStatement(ts) => {
ctx.push_scope();
self.predeclare_block_function_declarations(&ts.block.body, ctx);
ctx.pop_scope();
if let Some(handler) = &ts.handler {
ctx.push_scope();
self.predeclare_block_function_declarations(&handler.body.body, ctx);
ctx.pop_scope();
}
if let Some(finalizer) = &ts.finalizer {
ctx.push_scope();
self.predeclare_block_function_declarations(&finalizer.body, ctx);
ctx.pop_scope();
}
}
Statement::LabeledStatement(ls) => {
self.predeclare_block_function_declarations(std::slice::from_ref(&ls.body), ctx);
}
Statement::WithStatement(ws) => {
self.predeclare_block_function_declarations(std::slice::from_ref(&ws.body), ctx);
}
_ => {}
}
}
}
/// 预声明当前作用域直接子语句中的 `let`/`const`/`class` 绑定(未初始化,
/// 建立 TDZ 占位)。使声明点之前的读取在编译期可分辨为 TDZ 而非隐式全局,
/// 声明点复用预登记槽位。
///
/// # 边界与前提
/// - 只扫描直接子语句 + 递归 switch case(switch 不推 scope,case 内 lexical
/// 声明属于外层作用域);不递归块/if/for/while body(嵌套块自预声明;
/// 单语句 body 不接受 lexical 声明——lexical 属 Declaration、非 Statement
/// 子产生式,parser 按语法错误直接拒绝,这些形状不会进入 emit)。
/// - 跳过 for 头声明(循环作用域由 for 分支内联 declare)。
/// - `global_lexical` 为 true 时(仅脚本顶层调用点传 `!is_eval_script`):
/// lexical 声明撞受限全局名报 SyntaxError(脚本声明实例化对全局对象受限
/// 自有属性名做检查,eval 代码声明实例化无此检查);函数体/块/try/模块
/// 调用点传 false,lexical 声明是局部绑定不查。
pub(crate) fn predeclare_lexical_declarations(
&self, statements: &[Statement], ctx: &mut CompileCtx, global_lexical: bool,
) -> Result<(), String> {
for statement in statements {
match statement {
Statement::VariableDeclaration(decl) => {
if matches!(decl.kind, VariableDeclarationKind::Var) {
continue;
}
let is_const = matches!(decl.kind, VariableDeclarationKind::Const);
for d in &decl.declarations {
self.predeclare_lexical_pattern(&d.id, is_const, ctx, global_lexical)?;
}
}
Statement::ClassDeclaration(cd) => {
if let Some(id) = &cd.id {
check_restricted_global_lexical(id.name.as_str(), global_lexical)?;
let reg = ctx.alloc_reg();
let _ = ctx.declare_predeclared(id.name.as_str(), reg, VariableDeclarationKind::Const, true);
}
}
Statement::SwitchStatement(sw) => {
for case in &sw.cases {
for s in &case.consequent {
self.predeclare_lexical_stmt(s, ctx, global_lexical)?;
}
}
}
Statement::ExportNamedDeclaration(exp) => {
if let Some(decl) = &exp.declaration {
match decl {
Declaration::VariableDeclaration(vd) => {
if matches!(vd.kind, VariableDeclarationKind::Var) {
continue;
}
let is_const = matches!(vd.kind, VariableDeclarationKind::Const);
for d in &vd.declarations {
self.predeclare_lexical_pattern(&d.id, is_const, ctx, global_lexical)?;
}
}
Declaration::ClassDeclaration(cd) => {
if let Some(id) = &cd.id {
check_restricted_global_lexical(id.name.as_str(), global_lexical)?;
let reg = ctx.alloc_reg();
let _ = ctx.declare_predeclared(
id.name.as_str(),
reg,
VariableDeclarationKind::Const,
true,
);
}
}
_ => {}
}
}
}
Statement::ExportDefaultDeclaration(exp) => match &exp.declaration {
ExportDefaultDeclarationKind::ClassDeclaration(cd) => {
if let Some(id) = &cd.id {
check_restricted_global_lexical(id.name.as_str(), global_lexical)?;
let reg = ctx.alloc_reg();
let _ =
ctx.declare_predeclared(id.name.as_str(), reg, VariableDeclarationKind::Const, true);
}
}
ExportDefaultDeclarationKind::FunctionDeclaration(fd) => {
if let Some(id) = &fd.id {
let reg = ctx.alloc_reg();
let _ =
ctx.declare_predeclared(id.name.as_str(), reg, VariableDeclarationKind::Const, true);
}
}
_ => {}
},
_ => {}
}
}
Ok(())
}
/// 预声明单个语句中的 lexical 声明(供 switch case 递归;`let`/`const`/`class` 分支)。
fn predeclare_lexical_stmt(
&self, stmt: &Statement, ctx: &mut CompileCtx, global_lexical: bool,
) -> Result<(), String> {
match stmt {
Statement::VariableDeclaration(decl) => {
if matches!(decl.kind, VariableDeclarationKind::Var) {
return Ok(());
}
let is_const = matches!(decl.kind, VariableDeclarationKind::Const);
for d in &decl.declarations {
self.predeclare_lexical_pattern(&d.id, is_const, ctx, global_lexical)?;
}
}
Statement::ClassDeclaration(cd) => {
if let Some(id) = &cd.id {
check_restricted_global_lexical(id.name.as_str(), global_lexical)?;
let reg = ctx.alloc_reg();
let _ = ctx.declare_predeclared(id.name.as_str(), reg, VariableDeclarationKind::Const, true);
}
}
_ => {}
}
Ok(())
}
/// 递归预声明绑定 pattern 内的全部标识符(含数组/对象/默认值解构)。
fn predeclare_lexical_pattern(
&self, pattern: &BindingPattern, is_const: bool, ctx: &mut CompileCtx, global_lexical: bool,
) -> Result<(), String> {
match pattern {
BindingPattern::BindingIdentifier(bi) => {
check_restricted_global_lexical(bi.name.as_str(), global_lexical)?;
let reg = ctx.alloc_reg();
let _ = ctx.declare_predeclared(
bi.name.as_str(),
reg,
if is_const {
VariableDeclarationKind::Const
} else {
VariableDeclarationKind::Let
},
is_const,
);
}
BindingPattern::ArrayPattern(ap) => {
for e in ap.elements.iter().flatten() {
self.predeclare_lexical_pattern(e, is_const, ctx, global_lexical)?;
}
if let Some(rest) = &ap.rest {
self.predeclare_lexical_pattern(&rest.argument, is_const, ctx, global_lexical)?;
}
}
BindingPattern::ObjectPattern(op) => {
for prop in &op.properties {
self.predeclare_lexical_pattern(&prop.value, is_const, ctx, global_lexical)?;
}
if let Some(rest) = &op.rest {
self.predeclare_lexical_pattern(&rest.argument, is_const, ctx, global_lexical)?;
}
}
BindingPattern::AssignmentPattern(ap) => {
self.predeclare_lexical_pattern(&ap.left, is_const, ctx, global_lexical)?;
}
}
Ok(())
}
}