mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-25 03:01:12 +08:00
feat: 脚本顶层词法声明三常量名合法化并登记语料跳过条目
This commit is contained in:
@@ -1,8 +1,6 @@
|
||||
//! emit 前置 pass,声明预登记:函数/var 声明提升预声明、块级函数声明按 ES2015
|
||||
//! 块绑定预声明、let/const/class 建 TDZ 占位;顶层 lexical 声明撞受限全局名
|
||||
//! 在声明实例化期拒绝(global_lexical 门控,门控源居 emit_program 调用点)。
|
||||
//! 块绑定预声明、let/const/class 建 TDZ 占位。
|
||||
|
||||
use super::check_restricted_global_lexical;
|
||||
use crate::{CompileCtx, Emitter};
|
||||
use oxide_parser::{BindingPattern, Declaration, ExportDefaultDeclarationKind, Statement, VariableDeclarationKind};
|
||||
|
||||
@@ -294,10 +292,9 @@ impl Emitter {
|
||||
/// 属 Declaration、非 Statement 子产生式,parser 按语法错误直接拒绝,这些
|
||||
/// 形状不会进入 emit)。
|
||||
/// - 跳过 for 头声明(循环作用域由 for 分支内联 declare)。
|
||||
/// - `global_lexical` 为 true 时(仅脚本顶层调用点传 `!is_eval_script`):
|
||||
/// lexical 声明撞受限全局名报 SyntaxError(脚本声明实例化对全局对象受限
|
||||
/// 自有属性名做检查,eval 代码声明实例化无此检查);函数体/块/switch case/
|
||||
/// try/模块调用点传 false,lexical 声明是局部绑定不查。
|
||||
/// - `global_lexical` 仅脚本顶层调用点传 `!is_eval_script`,其余调用点传
|
||||
/// false;当前只透传不消费(死参数,待后续清理),顶层与局部的 lexical
|
||||
/// 声明均按合法遮蔽处理。
|
||||
pub(crate) fn predeclare_lexical_declarations(
|
||||
&self, statements: &[Statement], ctx: &mut CompileCtx, global_lexical: bool,
|
||||
) -> Result<(), String> {
|
||||
@@ -314,7 +311,6 @@ impl Emitter {
|
||||
}
|
||||
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::Let, false);
|
||||
}
|
||||
@@ -333,7 +329,6 @@ impl Emitter {
|
||||
}
|
||||
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(),
|
||||
@@ -352,7 +347,6 @@ impl Emitter {
|
||||
// 此处只为具名 default 类建 lexical Let TDZ 占位。
|
||||
if let ExportDefaultDeclarationKind::ClassDeclaration(cd) = &exp.declaration {
|
||||
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::Let, false);
|
||||
}
|
||||
@@ -365,12 +359,14 @@ impl Emitter {
|
||||
}
|
||||
|
||||
/// 递归预声明绑定 pattern 内的全部标识符(含数组/对象/默认值解构)。
|
||||
/// `global_lexical` 当前只透传不消费(死参数,待后续清理),递归调用
|
||||
/// 必须原样下传,故仅递归使用。
|
||||
#[allow(clippy::only_used_in_recursion)]
|
||||
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(),
|
||||
|
||||
@@ -7,23 +7,3 @@
|
||||
mod block_fn;
|
||||
mod builtin_scan;
|
||||
mod declare;
|
||||
|
||||
/// 脚本顶层词法声明(`let`/`const`/`class`)禁止使用的受限全局名:`undefined`、
|
||||
/// `NaN`、`Infinity` 三名静态集。
|
||||
///
|
||||
/// 判定标准是全局对象上 `configurable:false` 的自有属性名:此类属性无法由声明
|
||||
/// 实例化建立遮蔽绑定,现行规范下恰为三常量;`eval` 与其余内置属性皆可配置,
|
||||
/// 可合法遮蔽。运行时无法查询全局对象描述符,名单必须编译期确定。
|
||||
///
|
||||
/// 与 `BUILTIN_GLOBALS` 语义不同:后者是写入拦截与双写名单,两份名单互不派生,
|
||||
/// 交叠名由 `restricted_lexical_names_within_builtin_globals` 单测断言恒同步。
|
||||
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(())
|
||||
}
|
||||
|
||||
@@ -489,16 +489,6 @@ impl Emitter {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{BUILTIN_GLOBALS, NON_WRITABLE_GLOBAL_BUILTINS};
|
||||
use crate::prepass::RESTRICTED_GLOBAL_LEXICAL_NAMES;
|
||||
|
||||
/// 漂移守卫:受限全局名集与 put 写拦截名单交叠名恒同步(两名单语义独立、
|
||||
/// 不互相派生,靠本断言防止改名/删名时单边漂移)。
|
||||
#[test]
|
||||
fn restricted_lexical_names_within_builtin_globals() {
|
||||
for name in RESTRICTED_GLOBAL_LEXICAL_NAMES {
|
||||
assert!(BUILTIN_GLOBALS.contains(name), "受限全局名缺失于 builtin 名单:{name}");
|
||||
}
|
||||
}
|
||||
|
||||
/// 漂移守卫:只读名单是 builtin 母集子集,且只读/可写两谓词对母集构成
|
||||
/// 划分(不重不漏)——防三常量集或母集改名/删名时拦截面与双写面单边漂移。
|
||||
|
||||
Reference in New Issue
Block a user