cure_engine/lang.rs
1//! `Lang` trait:语言适配层。引擎的一切通用逻辑只通过它访问语言 AST。
2//!
3//! 结构契约:
4//! - 节点用稳定句柄 `Id`(语言侧 arena 索引),arena 只追加不回收,`Id` 永不失效;
5//! - children 顺序 = 书写/求值顺序(各 kind 的布局见 [`crate::kind::NodeKind`]);
6//! - `check` 阶段允许**追加**新节点(arena push),但不得改动既有结构;
7//! 结构变更只允许通过 `Edit` 在应用阶段发生。
8
9use std::fmt::Debug;
10use std::hash::Hash;
11
12use crate::effect::Effect;
13use crate::kind::{BinOp, LitRef, NodeKind, UnOp};
14
15pub trait Lang {
16 /// 稳定节点句柄(通常是 `Copy` 的索引 newtype)。
17 type Id: Copy + Eq + Hash + Ord + Debug;
18 /// 名字等价类句柄(Java:u32 intern id)。区域扫描的全部名字比较
19 /// 走它——语言侧应保证同名字同键、比较为整数等值(无字符串 memcmp)。
20 type NameKey: Copy + Eq + Ord + Debug;
21 /// 节点在语言 arena 中的稠密下标(供引擎位图/数组索引)。
22 fn node_index(&self, id: Self::Id) -> usize;
23 /// `node_index` 的逆映射(下标 → Id)。cure-tree 工具包的线性
24 /// 扫描(效果表重建、名字键扩展)需要按 arena 下标遍历。
25 fn id_of_index(&self, idx: usize) -> Self::Id;
26
27 // ---- 结构 ----
28
29 fn kind(&self, id: Self::Id) -> NodeKind;
30 fn children(&self, id: Self::Id) -> &[Self::Id];
31
32 /// 把 `parent` 的第 `index` 个孩子替换为 `new`。
33 fn set_child(&mut self, parent: Self::Id, index: usize, new: Self::Id);
34 /// 删除 `parent` 的第 `index` 个孩子。
35 fn remove_child(&mut self, parent: Self::Id, index: usize);
36 /// 从 `node` 的第 `index` 个孩子开始删 `remove` 个、插入 `insert`。
37 fn splice(&mut self, node: Self::Id, index: usize, remove: usize, insert: Vec<Self::Id>);
38
39 // ---- 构造 ----
40
41 fn build_return(&mut self, value: Option<Self::Id>) -> Self::Id;
42 fn build_block(&mut self, stmts: Vec<Self::Id>) -> Self::Id;
43 fn build_unary(&mut self, op: UnOp, operand: Self::Id) -> Self::Id;
44 fn build_bool(&mut self, v: bool) -> Self::Id;
45 /// 构造整数/long 字面量(常量折叠产物)。`long` 为 true 时带 L 语义。
46 fn build_int(&mut self, v: i64, long: bool) -> Self::Id;
47 /// 构造二元运算节点(常量折叠 / 取反重写等需要重建比较运算时使用)。
48 fn build_bin(&mut self, op: BinOp, l: Self::Id, r: Self::Id) -> Self::Id;
49 /// 构造三元表达式 `c ? a : b`(if→ternary 归并)。
50 fn build_ternary(&mut self, c: Self::Id, a: Self::Id, b: Self::Id) -> Self::Id;
51 /// 构造简单赋值 `target = value`(if→三元赋值归并)。
52 fn build_assign(&mut self, target: Self::Id, value: Self::Id) -> Self::Id;
53 /// 构造字符串字面量(字符串常量折叠产物)。
54 fn build_str(&mut self, s: &str) -> Self::Id;
55 /// 构造字符字面量(部分求值产物:`(char)('a'+1)` → 'b')。
56 fn build_char(&mut self, c: char) -> Self::Id;
57 /// 深拷贝子树(返回新 Id)。
58 fn copy_subtree(&mut self, id: Self::Id) -> Self::Id;
59
60 // ---- 语义查询 ----
61
62 /// 整棵子树的聚合效果(最坏情况)。语言侧应缓存(见 `prepare`)。
63 fn effect(&self, id: Self::Id) -> Effect;
64 /// 使 `id` 的聚合效果缓存失效(若有)。引擎在同 pass 批量应用编辑后
65 /// 沿祖先链调用——祖先的聚合效果含被改子树,必须失效,
66 /// 后续 `effect()` 读取回退为按需重算(子缓存仍有效,代价 O(孩子数))。
67 /// 默认空实现:无缓存的语言每次现算,天然正确。
68 fn invalidate_effect(&mut self, _id: Self::Id) {}
69
70 /// `id` 子树的区域事件序列(使用索引,prepare 期间预计算)。
71 /// 事件序必须等于 scan_region 原递归的遍历序;返回 None 表示该
72 /// 节点无索引(未构建/已失效)——scan_region 回退为原递归遍历。
73 /// 引擎在应用编辑后沿祖先链调用 invalidate_effect 使索引失效。
74 /// 事件索引一致性自检(惰性重建 B3 调试):默认空实现。
75 fn debug_verify_events(&self, _stmt: Self::Id) {}
76
77 fn region_events(
78 &self,
79 _id: Self::Id,
80 ) -> Option<&[crate::kind::RegionEvent<Self::Id, Self::NameKey>]> {
81 None
82 }
83 /// 节点的名字键(VarRef/VarDecl/ForEach/Catch 等命名节点);
84 /// 无名节点返回 None。
85 fn var_key(&self, _id: Self::Id) -> Option<Self::NameKey> {
86 None
87 }
88 /// 节点是否不透明(内部含不可解析原文,读/写集不可证明):
89 /// Java 的 Raw 节点与匿名类体(anon_raw)。区域用量分析的可靠性
90 /// 前提——漏判会导致捕获变量被误删(对抗波 4 抓获)。
91 fn is_opaque(&self, _id: Self::Id) -> bool {
92 false
93 }
94 /// 节点自身(不含 children)的效果贡献。
95 fn own_effect(&self, id: Self::Id) -> Effect {
96 match self.kind(id) {
97 NodeKind::Literal
98 | NodeKind::Paren
99 | NodeKind::This
100 | NodeKind::Block
101 | NodeKind::Empty
102 | NodeKind::VarDecl => Effect::Pure,
103 NodeKind::VarRef => Effect::MayRead,
104 NodeKind::Member => Effect::MayThrow,
105 NodeKind::Index | NodeKind::New => Effect::MayThrow,
106 NodeKind::Call => Effect::Unknown,
107 NodeKind::Assign => Effect::MayWrite,
108 NodeKind::Unary => {
109 if self.un_op(id).is_some_and(|o| o.is_incdec()) {
110 Effect::MayWrite
111 } else {
112 Effect::Pure
113 }
114 }
115 NodeKind::Binary => {
116 if self.bin_op(id).is_some_and(|o| o.may_div_zero()) {
117 Effect::MayThrow
118 } else {
119 Effect::Pure
120 }
121 }
122 NodeKind::Return | NodeKind::Throw => Effect::MayThrow,
123 NodeKind::Try | NodeKind::ForEach | NodeKind::Assert => Effect::MayThrow,
124 NodeKind::Catch | NodeKind::NewArray => Effect::MayThrow,
125 NodeKind::Synchronized => Effect::MayWrite,
126 NodeKind::Raw => Effect::Unknown,
127 _ => Effect::Unknown,
128 }
129 }
130
131 /// 表达式是否为**原始 boolean** 类型(装箱 Boolean 必须返回 false)。
132 fn is_bool(&self, id: Self::Id) -> bool;
133 /// 表达式是否具有精确整数类型(byte/short/int/long/char),用于算术恒等式守卫。
134 fn is_exact_int(&self, id: Self::Id) -> bool;
135 /// 是否为语言层的普通局部变量(可安全删除赋值;字段/全局必须 false)。
136 fn is_local_var(&self, id: Self::Id) -> bool {
137 self.kind(id) == NodeKind::VarRef
138 }
139
140 /// 声明(VarDecl 节点)的类型域是否容纳 int 算术结果。窄类型
141 /// (Java byte/short/char)的复合赋值含**隐式收窄**
142 /// (`b += K` ≡ `b = (byte)(b + K)`)——把 delta 折回声明会产出
143 /// 非法(超域常量)或变义(丢静态类型:`char ch = 99` 内联进
144 /// println 打数字而非字符)的字面量。默认 true(宽域语言)。
145 fn is_long_decl(&self, _decl: Self::Id) -> bool {
146 false
147 }
148 fn is_wide_decl(&self, _decl: Self::Id) -> bool {
149 true
150 }
151
152 /// 声明是否为**推断类型**(Java 10 `var`)。推断声明剥除 init 后
153 /// 变成 `var x;`——非法源码(obf_fuzz 差分抓获)。剥 init 类规则
154 /// 必须拒绝。默认 false。
155 fn is_inferred_decl(&self, _decl: Self::Id) -> bool {
156 false
157 }
158
159 /// 声明是否为字符类型。字符类型变量对 **int 字面量内联类型敏感**:
160 /// `char c = 98; println(c)` 打印 'b',而内联成 `println(98)` 打印
161 /// 98——静态类型可被 println / 字符串拼接观察。窄域规则(如
162 /// local_propagation)须拒绝非 Char 字面量值出字符声明。
163 fn is_char_decl(&self, _decl: Self::Id) -> bool {
164 false
165 }
166
167 /// 局部传播到**成员访问接收位**是否类型不可靠:声明的静态类型与
168 /// init 表达式的静态类型在成员解析上可能不等价(Java raw 泛型:
169 /// `List l = m(); l.add("x")` 的 raw 擦除收 Object,内联成
170 /// `m().add("x")` 后按泛型收 CAP#1 → javac 硬错——mockito
171 /// ReturningDefaultValuesTest 抓获)。仅接收位敏感(实参位 raw↔
172 /// 泛型双向兼容)。默认 false(无 raw 泛型的语言)。
173 fn receiver_propagation_unsound(
174 &self,
175 _decl: Self::Id,
176 _value: Self::Id,
177 _use_parent: Option<Self::Id>,
178 _use_at_head: bool,
179 ) -> bool {
180 false
181 }
182
183 fn bin_op(&self, id: Self::Id) -> Option<BinOp>;
184 fn un_op(&self, id: Self::Id) -> Option<UnOp>;
185 fn literal(&self, id: Self::Id) -> Option<LitRef<'_>>;
186 /// 变量相关名字:VarRef / VarDecl 读写的名字,以及 ForEach / Catch 的**声明绑定名**。
187 fn var_name(&self, id: Self::Id) -> Option<&str>;
188 /// 成员访问/方法引用的**成员名**(x.f / x.m() / X::m 的 f/m 部分)。
189 /// 结构相等性比较用(var_name 只覆盖 VarRef——x.a 与 x.b 曾被误判
190 /// 相等 → ternary_fold 删除活分支,Types.java Rewriter.high 抓获)。
191 fn member_name(&self, _id: Self::Id) -> Option<&str> {
192 None
193 }
194 /// 节点**负载**等价(NodeData 中的非孩子字段:New.ty/anon_raw、
195 /// Cast.ty、InstanceOf.ty/bind、Lambda.params_raw、VarDecl.ty 等)。
196 /// structurally_equal 用——负载不比较曾把 `cond ? new FairSync() :
197 /// new NonfairSync()`(参数相同、类型不同)判相等折叠:JDK 语料
198 /// 90 处真实误折(ReentrantReadWriteLock 锁公平性、DirectByteBuffer
199 /// 字节序、instanceof 守卫 cast → CCE,5 例运行时行为改变证实)。
200 fn payload_equal(&self, _a: Self::Id, _b: Self::Id) -> bool {
201 true
202 }
203 /// 名字是否是本单元声明的字段(字段读的可移动性判定——局部/参数
204 /// 不可被调用改变,字段可以)。默认 false(名字未声明 → 当作可移动,
205 /// 手工构建的 AST 无作用域解析时不会误伤)。
206 fn is_field_name(&self, _name: &str) -> bool {
207 false
208 }
209 /// 子树内是否含**模式绑定**(Java instanceof pattern:绑定作用域按
210 /// JLS 6.3 流可达性可越出语句本身到 enclosing block——块展平/语句
211 /// 移动类规则须拒绝。默认 false(无模式绑定的语言)。
212 fn has_pattern_bindings(&self, _root: Self::Id) -> bool {
213 false
214 }
215 /// 赋值运算(`=` 之外的复合赋值也在此表达;None 表示简单赋值)。
216 fn assign_op(&self, _id: Self::Id) -> Option<BinOp> {
217 None
218 }
219
220 // ---- 字面量折叠语义(数值/字符串语义全权归属语言侧)----
221 //
222 // 引擎规则只做**形态**匹配(双字面量、算符类别、代价门槛);一切
223 // 数值语义——宽度与环绕、除零策略、移位掩码、字符串拼接的强制
224 // 转换规则——由这些钩子的语言实现决定。默认全部不折(保守)。
225
226 /// 字面量二元折叠:算术/位运算/移位(`+ - * / % << >> >>> & | ^`)
227 /// 与字符串拼接。操作数为字面量节点 id;返回折叠产物节点。
228 fn fold_lit_bin(&mut self, _op: BinOp, _l: Self::Id, _r: Self::Id) -> Option<Self::Id> {
229 None
230 }
231
232 /// 字面量比较折叠(如 `1 < 2`)。可比较的字面量种类与字符串比较
233 /// 语义(引用比较 vs 值比较)由语言侧决定;返回布尔结果。
234 fn fold_lit_cmp(&mut self, _op: BinOp, _l: Self::Id, _r: Self::Id) -> Option<bool> {
235 None
236 }
237
238 /// 负数值字面量的取反(`-(-lit)` 外层负消除)。宽度溢出时必须
239 /// 返回 None 拒绝折叠(如 Java i32 的 `-(-2147483648)`)。
240 /// 默认实现按 i64 拒绝 `i64::MIN` 取反(防 debug panic / release 回绕)。
241 fn fold_lit_neg(&mut self, v: i64, _wide: bool) -> Option<i64> {
242 v.checked_neg()
243 }
244
245 /// 常量重结合合并:`(x op1 K1) op2 K2` 的常量合并结果。
246 /// 语言侧负责宽度回绕(Java i32 的 `K1+K2` 溢出必须回绕,否则
247 /// 产物是非法字面量)。
248 fn reassoc_delta(
249 &mut self,
250 _op1: BinOp,
251 _k1: i64,
252 _op2: BinOp,
253 _k2: i64,
254 _wide: bool,
255 ) -> Option<ReassocOutcome<Self::Id>> {
256 None
257 }
258
259 /// 每轮扫描前由引擎调用;语言侧在此刷新缓存(效果表、变量类型表等)。
260 /// `root` 是本轮简化的根(通常是方法体),语言侧可据此做作用域分析。
261 fn prepare(&mut self, _root: Self::Id) {}
262
263 /// 节点成本权重(用于“改写必须严格降本”的门槛)。
264 fn cost_weight(&self, kind: NodeKind) -> u64 {
265 crate::cost::default_weight(kind)
266 }
267}
268
269/// [`Lang::reassoc_delta`] 的合并结果。
270#[derive(Clone, Copy, Debug)]
271pub enum ReassocOutcome<Id> {
272 /// 合并为中性元(`(x+K1)-K1` 类)→ 直接替换为 `x`。
273 Neutral,
274 /// 合并后的常量字面量节点 + 建议算符(`x op lit`;负常量由语言侧
275 /// 决定用 `Sub` 正字面量还是 `Add` 负字面量表达)。
276 Lit(Id, BinOp),
277}