//! 常量折叠:操作数均为字面量且通过语义守卫时,编译期折成单常量, //! 发射单条 `LOAD_CONST`。折值编码逐运算符镜像运行时指令的产物编码, //! 保证物化后与运行时执行结果逐字节一致。 //! //! 三个域并列:数值域(`literal_constant`/`fold_binary`,两操作数形态, //! 守卫排除字符串与 BigInt)、字符串域(`literal_units`/`fold_string_chain`/ //! `fold_template`,Addition 链与全字面量模板,单元口径与运行期 //! `push_units_to` 逐段一致)、一元/逻辑/条件域(`literal_constant_wide`/ //! `fold_unary`/`fold_logical`/`fold_conditional`,全字面量操作数折单常量)。 //! //! 数值域语义守卫:任一操作数为 BigInt 字面量不折(BigInt 混合运行期抛 //! TypeError,BigInt 与 BigInt 有独立指令族);`DIV`/`MOD` 除数为零不折、 //! `EXP` 指数为负不折(保持运行时指令为除零/负指数编码的唯一来源)。 //! 字符串域语义守卫:Addition 链须至少一个字符串字面量(全数字链落回 //! 数值域与 `CONCAT_N`,两域零重叠);模板须全部 cooked 为 Some。 //! 一元/逻辑/条件域语义守卫:`+` 作用 BigInt 字面量不折(运行期抛 //! TypeError,保持运行时指令为该异常的唯一来源)。 use oxide_bytecode::module::Constant; use oxide_parser::{BinaryOperator, Expression, LogicalOperator, UnaryOperator}; use oxide_runtime_api::{ abstract_eq_primitives, bigint_to_string, js_number_to_string, relational_compare, strict_equality, to_boolean, to_int32, to_number, to_uint32, }; use oxide_types::string_forge::{decode_key, encode_key}; use oxide_types::value::JsValue; use crate::is_int_literal; use crate::shared::string_pool::{pool_key_marker, pool_key_plain}; /// 字面量表达式提取常量:剥括号与一元负号后,数字(`is_int_literal` 分派 /// `Int`/`Number`)、布尔、null 三类;BigInt 字面量、字符串字面量、RegExp 与 /// 非字面量一律 `None`。 /// /// 一元负号只沿 `UnaryNegation` 链剥(含嵌套负号与括号),其余一元运算符 /// (`!`/`typeof`/`void`/`~`/`+`/`delete`)终止剥壳不折。 pub(crate) fn literal_constant(expr: &Expression) -> Option { let (inner, negated) = peel_negation(expr); match inner { Expression::NumericLiteral(n) => { let value = if negated { -n.value } else { n.value }; if is_int_literal(value) { Some(Constant::Int(value as i32)) } else { Some(Constant::Number(value)) } } Expression::BooleanLiteral(b) if !negated => Some(Constant::Boolean(b.value)), Expression::NullLiteral(_) if !negated => Some(Constant::Null), _ => None, } } /// 剥括号与一元负号链:返回内层表达式与负号层数奇偶(奇数层取负)。 fn peel_negation<'a>(expr: &'a Expression<'a>) -> (&'a Expression<'a>, bool) { let mut e = expr; let mut negated = false; loop { while let Expression::ParenthesizedExpression(p) = e { e = &p.expression; } if let Expression::UnaryExpression(u) = e { if u.operator == UnaryOperator::UnaryNegation { negated = !negated; e = &u.argument; continue; } } break; } (e, negated) } /// 常量转 `JsValue`(纯 NaN-box 构造,零分配):`Int`/`Number`/`Boolean`/`Null` /// 四臂,其余臂不可达(BigInt/String/Undefined 已被守卫排除)。 fn const_to_jsvalue(c: &Constant) -> JsValue { match c { Constant::Int(i) => JsValue::int(*i), Constant::Number(d) => JsValue::float(*d), Constant::Boolean(b) => JsValue::bool(*b), Constant::Null => JsValue::null(), _ => unreachable!("折叠操作数守卫已排除 BigInt/String/Undefined"), } } /// 常量的数值(`Int`/`Number`/`Boolean`/`Null` 均走 `ToNumber` 口径)。 fn const_to_number(c: &Constant) -> f64 { to_number(const_to_jsvalue(c)) } /// 字面量表达式提取常量(宽口径):窄口径三臂加 BigInt 字面量臂,供一元/逻辑/ /// 条件折叠识别 BigInt 字面量(`+` 的 TypeError 守卫与 `-`/`~` 的 BigInt 折值 /// 都须知道操作数是 BigInt)。 /// /// 负零字面量(奇数层负号作用于 0 字面量)保 `Number(-0.0)` 不经 Int 臂,防 /// 符号丢失(`+`/`-` 折叠产物经 `Object.is` 可观察)。BigInt 字面量解析与 /// 字面量发射器同口径,解析失败返回 `None` 不折。 pub(crate) fn literal_constant_wide(expr: &Expression) -> Option { let (inner, negated) = peel_negation(expr); match inner { Expression::NumericLiteral(n) => { // 负零守卫:奇数层负号作用于 0 字面量保 Number(-0.0),Int 臂会丢符号。 if negated && n.value == 0.0 { return Some(Constant::Number(-0.0)); } let value = if negated { -n.value } else { n.value }; if is_int_literal(value) { Some(Constant::Int(value as i32)) } else { Some(Constant::Number(value)) } } Expression::BooleanLiteral(b) if !negated => Some(Constant::Boolean(b.value)), Expression::NullLiteral(_) if !negated => Some(Constant::Null), Expression::BigIntLiteral(b) => { let value = parse_bigint_literal(b)?; Some(if negated { Constant::BigInt(-value) } else { Constant::BigInt(value) }) } _ => None, } } /// BigInt 字面量解析:与字面量发射器同口径(i128 快路径失败回退十进制 /// `parse_bytes`,解析失败返回 `None` 不折)。 fn parse_bigint_literal(b: &oxide_parser::BigIntLiteral) -> Option { if let Ok(v) = b.value.parse::() { Some(num_bigint::BigInt::from(v)) } else { num_bigint::BigInt::parse_bytes(b.value.as_bytes(), 10) } } /// 常量的布尔值(`ToBoolean` 口径):BigInt 臂直接判零,其余经 /// `const_to_jsvalue` 加 `to_boolean`。 fn const_to_boolean(c: &Constant) -> bool { if let Constant::BigInt(b) = c { return *b != num_bigint::BigInt::from(0); } to_boolean(const_to_jsvalue(c)) } /// 双常量折叠分派:按操作码计算折值,守卫命中返回 `None`。 /// /// 折值编码逐运算符镜像运行时产物: /// - `ADD`:int+int 经 `checked_add` 在 i32 内保 `Int`,溢出升 `Number`(镜像 /// `int_add`);其余组合 f64 加(镜像 `dispatch_add` 的 `to_number` 路径) /// - `SUB`/`MUL`/`DIV`/`MOD`:恒 `Number`(镜像 `binary_arith!` 的 `as f64`) /// - `EXP`:恒 `Number` 的 `powf`(镜像 `exp_result`) /// - `BIT_AND`/`BIT_OR`/`BIT_XOR`/`SHL`/`SHR`:`Int`(镜像 `to_int32`) /// - `USHR`:结果 ≤ i32::MAX 保 `Int`,否则升 `Number`(镜像 `write_ushr_result`) /// - `LT`/`GT`/`LTE`/`GTE`:`Boolean`(镜像 `relational_compare`,GT/LTE 交换 /// 操作数,LTE/GTE 取反,`None` 归 false) /// - `EQ`/`NEQ`:`Boolean`(镜像 `abstract_eq` 原始值核心); /// `STRICT_EQ`/`STRICT_NEQ`:`Boolean`(镜像 `strict_equality`) /// /// 守卫:`DIV`/`MOD` 除数为零(`Int(0)` 与 `Number(±0.0)` 均判零)、`EXP` /// 指数为负(`Int`/`Number` 负值均判负)返回 `None`,落回运行时路径。 pub(crate) fn fold_binary(op: BinaryOperator, l: &Constant, r: &Constant) -> Option { match op { BinaryOperator::Addition => { // int+int:checked_add 在 i32 内保 Int,溢出升 f64(镜像 int_add)。 if let (Constant::Int(a), Constant::Int(b)) = (l, r) { return a .checked_add(*b) .map(Constant::Int) .or(Some(Constant::Number(*a as f64 + *b as f64))); } Some(Constant::Number(const_to_number(l) + const_to_number(r))) } BinaryOperator::Subtraction | BinaryOperator::Multiplication | BinaryOperator::Division | BinaryOperator::Remainder => { // 除零守卫:Int(0) 与 Number(±0.0) 均判零(v == 0.0 对 -0.0 亦真)。 if matches!(op, BinaryOperator::Division | BinaryOperator::Remainder) && const_to_number(r) == 0.0 { return None; } // 恒 f64(镜像 binary_arith! 宏的 as f64)。 let (ln, rn) = (const_to_number(l), const_to_number(r)); Some(match op { BinaryOperator::Subtraction => Constant::Number(ln - rn), BinaryOperator::Multiplication => Constant::Number(ln * rn), BinaryOperator::Division => Constant::Number(ln / rn), _ => Constant::Number(ln % rn), }) } BinaryOperator::Exponential => { // 负指数守卫:Int 与 Number 负值均判负。 if const_to_number(r) < 0.0 { return None; } // 恒 f64 powf(镜像 exp_result)。 Some(Constant::Number(const_to_number(l).powf(const_to_number(r)))) } BinaryOperator::BitwiseAnd | BinaryOperator::BitwiseOR | BinaryOperator::BitwiseXOR => { let (a, b) = (to_int32(const_to_jsvalue(l)), to_int32(const_to_jsvalue(r))); Some(match op { BinaryOperator::BitwiseAnd => Constant::Int(a & b), BinaryOperator::BitwiseOR => Constant::Int(a | b), _ => Constant::Int(a ^ b), }) } BinaryOperator::ShiftLeft | BinaryOperator::ShiftRight => { let a = to_int32(const_to_jsvalue(l)); let shift = to_uint32(const_to_jsvalue(r)) & 0x1F; Some(match op { BinaryOperator::ShiftLeft => Constant::Int(a << shift), _ => Constant::Int(a >> shift), }) } BinaryOperator::ShiftRightZeroFill => { let a = to_int32(const_to_jsvalue(l)) as u32; let shift = to_uint32(const_to_jsvalue(r)) & 0x1F; let result = a >> shift; // 结果 ≤ i32::MAX 保 Int,否则升 Number(镜像 write_ushr_result)。 if result <= i32::MAX as u32 { Some(Constant::Int(result as i32)) } else { Some(Constant::Number(result as f64)) } } BinaryOperator::LessThan => relational(l, r, false, false), BinaryOperator::GreaterThan => relational(l, r, true, false), BinaryOperator::LessEqualThan => relational(l, r, true, true), BinaryOperator::GreaterEqualThan => relational(l, r, false, true), BinaryOperator::Equality => { Some(Constant::Boolean(abstract_eq_primitives(const_to_jsvalue(l), const_to_jsvalue(r)))) } BinaryOperator::Inequality => { Some(Constant::Boolean(!abstract_eq_primitives(const_to_jsvalue(l), const_to_jsvalue(r)))) } BinaryOperator::StrictEquality => { Some(Constant::Boolean(strict_equality(const_to_jsvalue(l), const_to_jsvalue(r)))) } BinaryOperator::StrictInequality => { Some(Constant::Boolean(!strict_equality(const_to_jsvalue(l), const_to_jsvalue(r)))) } // IN/INSTANCEOF 是对象操作,不折。 BinaryOperator::In | BinaryOperator::Instanceof => None, } } /// 关系比较折叠:镜像运行时 dispatch 口径(GT/LTE 交换操作数,LTE/GTE 取反, /// `None` 归 false)。 fn relational(l: &Constant, r: &Constant, swap: bool, negate: bool) -> Option { let (a, b) = if swap { (const_to_jsvalue(r), const_to_jsvalue(l)) } else { (const_to_jsvalue(l), const_to_jsvalue(r)) }; let cmp = relational_compare(a, b).unwrap_or(false); Some(Constant::Boolean(if negate { !cmp } else { cmp })) } /// 一元折叠分派:按操作符计算折值,守卫命中返回 `None`。 /// /// 折值编码逐运算符镜像运行时产物: /// - `LogicalNot`:`Boolean`(镜像 `NOT` 的 `to_boolean` 取反) /// - `UnaryNegation`:BigInt 操作数折 `BigInt`,其余恒 `Number`(镜像 /// `NEG` 的 `JsValue::float`,不保 `Int`) /// - `UnaryPlus`:BigInt 操作数不折(运行期抛 TypeError,保持运行时指令为 /// 该异常的唯一来源);其余恒 `Number` /// - `BitwiseNot`:BigInt 操作数折 `BigInt`,其余恒 `Int`(镜像 `to_int32`) /// - `Typeof`:`Int`/`Number` 折 "number"、`BigInt` 折 "bigint"、`Boolean` 折 /// "boolean"、`Null` 折 "object"(结果字符串经 `pool_key_plain` 入池,逐类型 /// 镜像运行时 `TYPEOF_TEXTS` 分派) /// - `Void`:恒 `Undefined` /// - `Delete`:引用语义非常量,不折(入口 Delete 特判先行,此臂为防御) pub(crate) fn fold_unary(op: UnaryOperator, c: &Constant) -> Option { match op { UnaryOperator::LogicalNot => Some(Constant::Boolean(!const_to_boolean(c))), UnaryOperator::UnaryNegation => match c { Constant::BigInt(b) => Some(Constant::BigInt(-b.clone())), _ => Some(Constant::Number(-const_to_number(c))), }, UnaryOperator::UnaryPlus => { // BigInt 守卫:运行期抛 TypeError,不折。 if matches!(c, Constant::BigInt(_)) { return None; } Some(Constant::Number(const_to_number(c))) } UnaryOperator::BitwiseNot => match c { Constant::BigInt(b) => Some(Constant::BigInt(!b.clone())), _ => Some(Constant::Int(!to_int32(const_to_jsvalue(c)))), }, UnaryOperator::Typeof => { // 逐类型镜像运行时 `TYPEOF_TEXTS` 分派:BigInt 归 "bigint" // (独立于 Int/Double 的 "number"),Boolean 归 "boolean",Null 归 "object"。 let text = match c { Constant::Int(_) | Constant::Number(_) => "number", Constant::BigInt(_) => "bigint", Constant::Boolean(_) => "boolean", Constant::Null => "object", _ => return None, }; Some(Constant::String(pool_key_plain(text))) } UnaryOperator::Void => Some(Constant::Undefined), UnaryOperator::Delete => None, } } /// 逻辑折叠分派:结果恒为某一操作数的原样拷贝(无类型转换,任何字面量类型 /// 均安全,含 BigInt)。 pub(crate) fn fold_logical(op: LogicalOperator, l: &Constant, r: &Constant) -> Option { Some(match op { LogicalOperator::And => { if const_to_boolean(l) { r.clone() } else { l.clone() } } LogicalOperator::Or => { if const_to_boolean(l) { l.clone() } else { r.clone() } } LogicalOperator::Coalesce => { if matches!(l, Constant::Null | Constant::Undefined) { r.clone() } else { l.clone() } } }) } /// 条件折叠分派:结果恒为 test 的布尔值选定的分支常量(原样拷贝)。 pub(crate) fn fold_conditional(test: &Constant, cons: &Constant, alt: &Constant) -> Option { Some(if const_to_boolean(test) { cons.clone() } else { alt.clone() }) } /// 可折叠字面量的单元序列(剥括号与一元负号链):字符串字面量经 /// `pool_key_marker` 加 `decode_key` 还原单元(与字面量发射器同一池键函数); /// 数字字面量按 `is_int_literal` 分派 i32 itoa 或 `js_number_to_string` 后 /// UTF-16 编码;BigInt 字面量解析后 `bigint_to_string`(i128 快路径失败回退 /// 十进制 `parse_bytes`,解析失败返回 `None` 不折);布尔与 null 为 /// "true"/"false"/"null"。 /// /// 其余形态(标识符/调用/RegExp/嵌套二元等)返回 `None`。 pub(crate) fn literal_units(expr: &Expression) -> Option> { let (inner, negated) = peel_negation(expr); match inner { Expression::StringLiteral(s) if !negated => Some(decode_key(&pool_key_marker(&s.value, s.lone_surrogates))), Expression::NumericLiteral(n) => { let value = if negated { -n.value } else { n.value }; let text = if is_int_literal(value) { (value as i32).to_string() } else { js_number_to_string(value) }; Some(text.encode_utf16().collect()) } Expression::BigIntLiteral(b) => { let value = if let Ok(v) = b.value.parse::() { num_bigint::BigInt::from(v) } else { num_bigint::BigInt::parse_bytes(b.value.as_bytes(), 10)? }; let value = if negated { -value } else { value }; Some(bigint_to_string(&value).encode_utf16().collect()) } Expression::BooleanLiteral(b) if !negated => { let text = if b.value { "true" } else { "false" }; Some(text.encode_utf16().collect()) } Expression::NullLiteral(_) if !negated => Some("null".encode_utf16().collect()), _ => None, } } /// 判定操作数是否为字符串字面量(剥括号):规范判定整条 `+` 链为字符串 /// 拼接的条件。 fn is_string_literal(expr: &Expression) -> bool { let mut e = expr; while let Expression::ParenthesizedExpression(p) = e { e = &p.expression; } matches!(e, Expression::StringLiteral(_)) } /// Addition 链字符串域折叠:全操作数经 `literal_units` 可定值且至少一个是 /// 字符串字面量时,拼接各段单元经 `encode_key` 回池键形态,返回 /// `Constant::String`;全数字链(无字符串字面量)返回 `None` 落回 `CONCAT_N`。 pub(crate) fn fold_string_chain(operands: &[&Expression]) -> Option { // 字符串域守卫置于首行:至少一个字符串字面量,全数字链留给数值域。 if !operands.iter().any(|op| is_string_literal(op)) { return None; } let mut units: Vec = Vec::new(); for op in operands { units.extend(literal_units(op)?); } Some(Constant::String(encode_key(&units))) } /// 模板字面量折叠:全部 quasi 的 cooked 为 Some 且全部内插表达式经 /// `literal_units` 可定值时,按 quasi 与表达式交替序拼接单元经 `encode_key` /// 回池键形态,返回 `Constant::String`;任一 cooked 为 None(非法转义, /// 解析期 SyntaxError 的防御路径)返回 `None` 落回 `TEMPLATE_STR`。 pub(crate) fn fold_template(tl: &oxide_parser::TemplateLiteral) -> Option { // cooked 守卫置于首行:任一段为 None 时整模板不折。 if !tl.quasis.iter().all(|q| q.value.cooked.is_some()) { return None; } let mut units: Vec = Vec::new(); for (i, q) in tl.quasis.iter().enumerate() { let cooked = q.value.cooked.as_ref().expect("守卫已确认全部 cooked 为 Some"); units.extend(decode_key(&pool_key_marker(cooked, q.lone_surrogates))); if let Some(expr) = tl.expressions.get(i) { units.extend(literal_units(expr)?); } } Some(Constant::String(encode_key(&units))) }