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

752 lines
36 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::{
BindingPattern, Declaration, ExportDefaultDeclarationKind, Expression, Statement, VariableDeclarationKind,
};
/// 脚本顶层 lexical 声明(let/const/class)禁止使用的受限全局名:3 名静态集。
/// 受限判定走规范自有属性臂:全局对象上 {configurable:false} 自有属性名(声明
/// 实例化无法建立遮蔽绑定)——现行规范下恰为三常量;eval 与各 builtin 属性皆
/// 可配置(合法遮蔽),不在此列。名基静态集(编译期不可查运行时描述符)。与
/// BUILTIN_GLOBALS 语义不同(后者是 put 写拦截/双写名单),不互相派生,交叠
/// 名由漂移守卫单测断言恒同步。
pub(crate) const RESTRICTED_GLOBAL_LEXICAL_NAMES: &[&str] = &["undefined", "NaN", "Infinity"];
/// 脚本顶层 lexical 声明撞受限全局名 → SyntaxError(声明实例化期拒绝,整程序
/// 编译失败)。错误消息与既有重复声明错同形;非顶层或名不在受限集 → Ok。
fn check_restricted_global_lexical(name: &str, global_lexical: bool) -> Result<(), String> {
if global_lexical && RESTRICTED_GLOBAL_LEXICAL_NAMES.contains(&name) {
return Err(format!("Identifier '{name}' has already been declared"));
}
Ok(())
}
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 {
self.pre_scan_builtin_pattern(&d.id, ctx);
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 {
self.pre_scan_builtin_pattern(&d.id, ctx);
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) => {
if let oxide_parser::ForStatementLeft::VariableDeclaration(vd) = &fi.left {
for d in &vd.declarations {
self.pre_scan_builtin_pattern(&d.id, ctx);
}
}
self.pre_scan_builtin_expr(&fi.right, ctx);
self.pre_scan_builtin_stmt(&fi.body, ctx);
}
Statement::ForOfStatement(fo) => {
if let oxide_parser::ForStatementLeft::VariableDeclaration(vd) = &fo.left {
for d in &vd.declarations {
self.pre_scan_builtin_pattern(&d.id, ctx);
}
}
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 {
if let Some(param) = &handler.param {
self.pre_scan_builtin_pattern(&param.pattern, ctx);
}
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::WithStatement(ws) => {
self.pre_scan_builtin_expr(&ws.object, ctx);
self.pre_scan_builtin_stmt(&ws.body, ctx);
}
Statement::ClassDeclaration(cd) => {
if let Some(super_class) = &cd.super_class {
self.pre_scan_builtin_expr(super_class, ctx);
}
}
Statement::ExportNamedDeclaration(exp) => {
if let Some(Declaration::VariableDeclaration(vd)) = &exp.declaration {
for d in &vd.declarations {
self.pre_scan_builtin_pattern(&d.id, ctx);
if let Some(init) = &d.init {
self.pre_scan_builtin_expr(init, ctx);
}
}
}
}
Statement::ExportDefaultDeclaration(exp) => {
if let Some(e) = exp.declaration.as_expression() {
self.pre_scan_builtin_expr(e, 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 {
match prop {
oxide_parser::ObjectPropertyKind::ObjectProperty(p) => {
if p.computed {
self.pre_scan_builtin_expr(p.key.to_expression(), ctx);
}
self.pre_scan_builtin_expr(&p.value, ctx);
}
oxide_parser::ObjectPropertyKind::SpreadProperty(spread) => {
self.pre_scan_builtin_expr(&spread.argument, 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::YieldExpression(ye) => {
if let Some(a) = &ye.argument {
self.pre_scan_builtin_expr(a, ctx);
}
}
Expression::AwaitExpression(ae) => self.pre_scan_builtin_expr(&ae.argument, 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::AssignmentTargetIdentifier(id) => {
// 标识符目标与表达式位置标识符引用同口径预登记:目标为某内置名的
// 唯一出现处(无读侧引用)时缺预登记会解析成隐式全局新槽,旧值读
// 与短路判定拿到未预载值。
if CompileCtx::is_known_builtin(id.name.as_str()) {
let _ = ctx.lookup_or_builtin(id.name.as_str());
}
}
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);
}
}
/// 遍历绑定 pattern 的计算键表达式(`{[k]: a}` 的键)里的 builtin 引用:
/// 模式键是运行时求值表达式,键内 builtin 标识符须预先登记固定槽位
/// (与对象字面量计算键预扫描同口径)。
fn pre_scan_builtin_pattern(&self, pattern: &BindingPattern, ctx: &mut CompileCtx) {
match pattern {
BindingPattern::BindingIdentifier(_) => {}
BindingPattern::ArrayPattern(ap) => {
for e in ap.elements.iter().flatten() {
self.pre_scan_builtin_pattern(e, ctx);
}
if let Some(rest) = &ap.rest {
self.pre_scan_builtin_pattern(&rest.argument, ctx);
}
}
BindingPattern::ObjectPattern(op) => {
for prop in &op.properties {
if prop.computed {
self.pre_scan_builtin_expr(prop.key.to_expression(), ctx);
}
self.pre_scan_builtin_pattern(&prop.value, ctx);
}
if let Some(rest) = &op.rest {
self.pre_scan_builtin_pattern(&rest.argument, ctx);
}
}
BindingPattern::AssignmentPattern(ap) => {
self.pre_scan_builtin_pattern(&ap.left, ctx);
}
}
}
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);
}
}
/// 预声明单个 `var` 名:仅顶层(全局作用域)的 builtin 名落 builtin 镜像槽
/// (run 起点预载全局属性值),使 GDI 序言与声明点同步都用入口原值而非
/// fresh undefined 槽,现存值(NaN 等)不被抹;函数体内 builtin 名仍是局部
/// var 遮蔽(fresh 槽,不命中只读内置拦截);其余名 fresh var 槽。
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(())
}
}