Skip to main content

cure_engine/
pattern.rs

1//! 最小 Pattern DSL:静态可构造的树形模式 + 绑定。
2//!
3//! 复杂规则仍可直接在 `Rule::check` 里手写结构判断;这里的目的是
4//! 让“形状”类规则摆脱 if-let 嵌套,且 `Pat` 是纯数据、未来可序列化成声明式规则。
5
6use crate::kind::{LitRef, NodeKind};
7use crate::lang::Lang;
8
9#[derive(Debug)]
10pub enum Pat {
11    /// 任意节点。
12    Any,
13    /// 绑定当前节点 id 到名字。
14    Bind(&'static str),
15    /// 节点 kind 匹配且 children 与 pats 一一同数量、按序匹配。
16    Kind(NodeKind, &'static [Pat]),
17    /// boolean 字面量。
18    LitBool(bool),
19    /// 整数字面量(Int/Long)值匹配。
20    LitInt(i64),
21}
22
23pub type Binds<L> = Vec<(&'static str, <L as Lang>::Id)>;
24
25pub fn match_pat<L: Lang>(lang: &L, id: L::Id, pat: &Pat, binds: &mut Binds<L>) -> bool {
26    match pat {
27        Pat::Any => true,
28        Pat::Bind(name) => {
29            binds.push((name, id));
30            true
31        }
32        Pat::LitBool(v) => matches!(lang.literal(id), Some(LitRef::Bool(b)) if b == *v),
33        Pat::LitInt(v) => lang.literal(id).and_then(|l| l.as_int()) == Some(*v),
34        Pat::Kind(kind, pats) => {
35            if lang.kind(id) != *kind {
36                return false;
37            }
38            let children = lang.children(id);
39            if children.len() != pats.len() {
40                return false;
41            }
42            children
43                .iter()
44                .zip(pats.iter())
45                .all(|(&c, p)| match_pat(lang, c, p, binds))
46        }
47    }
48}
49
50/// 便捷入口:匹配成功返回绑定表。
51pub fn matches<L: Lang>(lang: &L, id: L::Id, pat: &Pat) -> Option<Binds<L>> {
52    let mut binds: Binds<L> = Vec::new();
53    if match_pat(lang, id, pat, &mut binds) {
54        Some(binds)
55    } else {
56        None
57    }
58}
59
60impl Pat {
61    pub fn bind(name: &'static str) -> Pat {
62        Pat::Bind(name)
63    }
64    pub fn kind(k: NodeKind, pats: &'static [Pat]) -> Pat {
65        Pat::Kind(k, pats)
66    }
67}
68
69#[macro_export]
70/// 静态声明一个 Pat 常量,如:
71/// `pat!(IF_RET_TF, Kind(If, [Bind("cond"), Kind(Return, [LitBool(true)])…]))`。
72macro_rules! pat {
73    ($name:ident, $($tok:tt)*) => {
74        static $name: $crate::pattern::Pat = $crate::pattern::__pat!($($tok)*);
75    };
76}
77
78#[doc(hidden)]
79#[macro_export]
80macro_rules! __pat {
81    (Any) => { $crate::pattern::Pat::Any };
82    (Bind($n:literal)) => { $crate::pattern::Pat::Bind($n) };
83    (LitBool($v:literal)) => { $crate::pattern::Pat::LitBool($v) };
84    (LitInt($v:literal)) => { $crate::pattern::Pat::LitInt($v) };
85    (Kind($k:expr, [$($p:tt),* $(,)?])) => {
86        $crate::pattern::Pat::Kind($k, &[$($crate::__pat!($p)),*])
87    };
88}