dfir_datalog_core/
grammar.rs

1#[rust_sitter::grammar("datalog")]
2// #[expect(dead_code)]
3pub mod datalog {
4    use rust_sitter::Spanned;
5
6    #[rust_sitter::language]
7    #[derive(Debug)]
8    pub struct Program {
9        pub rules: Vec<Declaration>,
10    }
11
12    #[derive(Debug, Clone)]
13    pub enum Declaration {
14        Input(
15            #[rust_sitter::leaf(text = ".input")] (),
16            Spanned<Ident>,
17            RustSnippet,
18        ),
19        Output(
20            #[rust_sitter::leaf(text = ".output")] (),
21            Spanned<Ident>,
22            RustSnippet,
23        ),
24        Persist(#[rust_sitter::leaf(text = ".persist")] (), Spanned<Ident>),
25        Async(
26            #[rust_sitter::leaf(text = ".async")] (),
27            Spanned<Ident>,
28            /// A pipeline for data to be sent to another node, which must consume `(NodeID, Data)` pairs.
29            RustSnippet,
30            /// A pipeline for data received from another node, which must produce `Data` values.
31            RustSnippet,
32        ),
33        Rule(Spanned<Rule>),
34        Static(
35            #[rust_sitter::leaf(text = ".static")] (),
36            Spanned<Ident>,
37            RustSnippet,
38        ),
39    }
40
41    #[derive(Debug, Clone)]
42    pub struct RustSnippet {
43        #[rust_sitter::leaf(text = "`")]
44        _start: (),
45        #[rust_sitter::leaf(pattern = r#"[^`]*"#, transform = |s| s.to_string())]
46        pub code: Spanned<String>,
47        #[rust_sitter::leaf(text = "`")]
48        _end: (),
49    }
50
51    #[derive(Debug, Clone)]
52    pub struct Rule {
53        pub target: TargetRelationExpr,
54
55        pub rule_type: Spanned<RuleType>,
56
57        #[rust_sitter::repeat(non_empty = true)]
58        #[rust_sitter::delimited(
59            #[rust_sitter::leaf(text = ",")]
60            ()
61        )]
62        pub sources: Vec<Atom>,
63
64        #[rust_sitter::leaf(text = ".")]
65        _dot: Option<()>,
66    }
67
68    #[derive(Debug, Clone)]
69    pub enum RuleType {
70        Sync(#[rust_sitter::leaf(text = ":-")] ()),
71        NextTick(#[rust_sitter::leaf(text = ":+")] ()),
72        Async(#[rust_sitter::leaf(text = ":~")] ()),
73    }
74
75    #[derive(Debug, Clone)]
76    pub enum Atom {
77        NegRelation(
78            #[rust_sitter::leaf(text = "!")] (),
79            Spanned<InputRelationExpr>,
80        ),
81        PosRelation(Spanned<InputRelationExpr>),
82        Predicate(Spanned<BoolExpr>),
83    }
84
85    #[derive(Debug, Clone)]
86    pub enum ExtractExpr {
87        Ident(Spanned<Ident>),
88        #[expect(dead_code, reason = "unused spanned")]
89        Underscore(#[rust_sitter::leaf(text = "_")] Spanned<()>),
90        Flatten(#[rust_sitter::leaf(text = "*")] (), Box<ExtractExpr>),
91        Untuple(
92            #[rust_sitter::leaf(text = "(")] (),
93            #[rust_sitter::delimited(
94                #[rust_sitter::leaf(text = ",")]
95                ()
96            )]
97            Vec<Spanned<ExtractExpr>>,
98            #[rust_sitter::leaf(text = ")")] (),
99        ),
100    }
101
102    #[derive(Debug, Clone)]
103    pub struct InputRelationExpr {
104        pub name: Spanned<Ident>,
105
106        #[rust_sitter::leaf(text = "(")]
107        _l_paren: (),
108
109        #[rust_sitter::delimited(
110            #[rust_sitter::leaf(text = ",")]
111            ()
112        )]
113        pub fields: Vec<Spanned<ExtractExpr>>,
114
115        #[rust_sitter::leaf(text = ")")]
116        _r_paren: (),
117    }
118
119    #[derive(Debug, Clone)]
120    pub struct TargetRelationExpr {
121        pub name: Spanned<Ident>,
122
123        pub at_node: Option<AtNode>,
124
125        #[rust_sitter::leaf(text = "(")]
126        _l_paren: (),
127
128        #[rust_sitter::delimited(
129            #[rust_sitter::leaf(text = ",")]
130            ()
131        )]
132        pub fields: Vec<Spanned<TargetExpr>>,
133
134        #[rust_sitter::leaf(text = ")")]
135        _r_paren: (),
136    }
137
138    #[derive(Debug, Clone)]
139    pub struct AtNode {
140        #[rust_sitter::leaf(text = "@")]
141        _at: (),
142
143        pub node: Spanned<TargetExpr>,
144    }
145
146    #[derive(Debug, Clone)]
147    pub enum TargetExpr {
148        Expr(IntExpr),
149        Aggregation(Aggregation),
150        Index(
151            #[rust_sitter::leaf(text = "index")] (),
152            #[rust_sitter::leaf(text = "(")] (),
153            #[rust_sitter::leaf(text = ")")] (),
154        ),
155    }
156
157    impl TargetExpr {
158        pub fn idents(&self) -> Vec<&Ident> {
159            match self {
160                TargetExpr::Expr(e) => e.idents(),
161                TargetExpr::Aggregation(Aggregation::Count(_)) => vec![],
162                TargetExpr::Aggregation(
163                    Aggregation::CountUnique(_, _, idents, _)
164                    | Aggregation::CollectVec(_, _, idents, _),
165                ) => idents.iter().map(|i| &i.value).collect(),
166                TargetExpr::Aggregation(
167                    Aggregation::Min(_, _, a, _)
168                    | Aggregation::Max(_, _, a, _)
169                    | Aggregation::Sum(_, _, a, _)
170                    | Aggregation::Choose(_, _, a, _),
171                ) => vec![a],
172                TargetExpr::Index(_, _, _) => vec![],
173            }
174        }
175    }
176
177    #[derive(Debug, Clone)]
178    pub enum Aggregation {
179        Min(
180            #[rust_sitter::leaf(text = "min")] (),
181            #[rust_sitter::leaf(text = "(")] (),
182            Spanned<Ident>,
183            #[rust_sitter::leaf(text = ")")] (),
184        ),
185        Max(
186            #[rust_sitter::leaf(text = "max")] (),
187            #[rust_sitter::leaf(text = "(")] (),
188            Spanned<Ident>,
189            #[rust_sitter::leaf(text = ")")] (),
190        ),
191        Sum(
192            #[rust_sitter::leaf(text = "sum")] (),
193            #[rust_sitter::leaf(text = "(")] (),
194            Spanned<Ident>,
195            #[rust_sitter::leaf(text = ")")] (),
196        ),
197        Count(#[rust_sitter::leaf(text = "count(*)")] ()),
198        CountUnique(
199            #[rust_sitter::leaf(text = "count")] (),
200            #[rust_sitter::leaf(text = "(")] (),
201            #[rust_sitter::delimited(
202                #[rust_sitter::leaf(text = ",")]
203                ()
204            )]
205            Vec<Spanned<Ident>>,
206            #[rust_sitter::leaf(text = ")")] (),
207        ),
208        Choose(
209            #[rust_sitter::leaf(text = "choose")] (),
210            #[rust_sitter::leaf(text = "(")] (),
211            Spanned<Ident>,
212            #[rust_sitter::leaf(text = ")")] (),
213        ),
214        CollectVec(
215            #[rust_sitter::leaf(text = "collect_vec")] (),
216            #[rust_sitter::leaf(text = "(")] (),
217            #[rust_sitter::delimited(
218                #[rust_sitter::leaf(text = ",")]
219                ()
220            )]
221            Vec<Spanned<Ident>>,
222            #[rust_sitter::leaf(text = ")")] (),
223        ),
224    }
225
226    #[derive(Clone, PartialEq, Eq, Hash, Ord, PartialOrd, Debug)]
227    pub struct Ident {
228        #[rust_sitter::leaf(pattern = r"[a-zA-Z][a-zA-Z0-9_]*", transform = |s| s.to_string())]
229        pub name: String,
230    }
231
232    #[rust_sitter::extra]
233    struct Whitespace {
234        #[rust_sitter::leaf(pattern = r"\s")]
235        _whitespace: (),
236    }
237
238    #[rust_sitter::extra]
239    struct Comment {
240        #[rust_sitter::leaf(pattern = r"(#|\/\/).*")]
241        _comment: (),
242    }
243
244    #[derive(Debug, Clone)]
245    pub enum BoolOp {
246        Lt(#[rust_sitter::leaf(text = "<")] ()),
247        LtEq(#[rust_sitter::leaf(text = "<=")] ()),
248        Gt(#[rust_sitter::leaf(text = ">")] ()),
249        GtEq(#[rust_sitter::leaf(text = ">=")] ()),
250        Eq(#[rust_sitter::leaf(text = "==")] ()),
251        Neq(#[rust_sitter::leaf(text = "!=")] ()),
252    }
253
254    #[derive(Debug, Clone)]
255    pub struct BoolExpr {
256        #[rust_sitter::leaf(text = "(")]
257        _l_brace: (),
258
259        pub left: Spanned<IntExpr>,
260        pub op: BoolOp,
261        pub right: Spanned<IntExpr>,
262
263        #[rust_sitter::leaf(text = ")")]
264        _r_brace: (),
265    }
266
267    #[derive(Debug, Clone)]
268    pub enum IntExpr {
269        Ident(Spanned<Ident>),
270        Integer(
271            #[rust_sitter::leaf(pattern = r"[0-9]+", transform = |s| s.parse().unwrap())]
272            Spanned<i64>,
273        ),
274        Parenthesized(
275            #[rust_sitter::leaf(text = "(")] (),
276            Box<IntExpr>,
277            #[rust_sitter::leaf(text = ")")] (),
278        ),
279        #[rust_sitter::prec_left(1)]
280        Add(
281            Box<IntExpr>,
282            #[rust_sitter::leaf(text = "+")] (),
283            Box<IntExpr>,
284        ),
285        #[rust_sitter::prec_left(1)]
286        Sub(
287            Box<IntExpr>,
288            #[rust_sitter::leaf(text = "-")] (),
289            Box<IntExpr>,
290        ),
291        #[rust_sitter::prec_left(2)]
292        Mul(
293            Box<IntExpr>,
294            #[rust_sitter::leaf(text = "*")] (),
295            Box<IntExpr>,
296        ),
297        #[rust_sitter::prec_left(1)]
298        Mod(
299            Box<IntExpr>,
300            #[rust_sitter::leaf(text = "%")] (),
301            Box<IntExpr>,
302        ),
303    }
304
305    impl IntExpr {
306        pub fn idents(&self) -> Vec<&Ident> {
307            match self {
308                IntExpr::Ident(i) => vec![i],
309                IntExpr::Integer(_) => vec![],
310                IntExpr::Parenthesized(_, e, _) => e.idents(),
311                IntExpr::Add(l, _, r) => {
312                    let mut idents = l.idents();
313                    idents.extend(r.idents());
314                    idents
315                }
316                IntExpr::Sub(l, _, r) => {
317                    let mut idents = l.idents();
318                    idents.extend(r.idents());
319                    idents
320                }
321                IntExpr::Mul(l, _, r) => {
322                    let mut idents = l.idents();
323                    idents.extend(r.idents());
324                    idents
325                }
326                IntExpr::Mod(l, _, r) => {
327                    let mut idents = l.idents();
328                    idents.extend(r.idents());
329                    idents
330                }
331            }
332        }
333    }
334}