Skip to main content

mangle_ir/
physical.rs

1// Copyright 2025 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Physical Plan IR for Mangle.
16//!
17//! This represents the imperative execution logic (loops, joins, inserts)
18//! derived from the declarative logical IR.
19
20use crate::{NameId, StringId};
21
22#[derive(Debug, Clone, PartialEq)]
23pub enum Op {
24    /// A no-op.
25    Nop,
26
27    /// Sequence of operations executed in order.
28    Seq(Vec<Op>),
29
30    /// Iterate over a data source.
31    /// For each tuple yielded by `source`, `body` is executed.
32    /// Variables defined in `source` are bound and available in `body`.
33    Iterate { source: DataSource, body: Box<Op> },
34
35    /// Filter / Check condition.
36    /// If `cond` evaluates to true, `body` is executed.
37    Filter { cond: Condition, body: Box<Op> },
38
39    /// Insert a tuple into a relation.
40    /// All variables in `args` must be bound.
41    Insert {
42        relation: NameId,
43        args: Vec<Operand>,
44    },
45
46    /// Calculate a value and bind it to a variable.
47    /// `let var = expr`
48    Let {
49        var: NameId,
50        expr: Expr,
51        body: Box<Op>,
52    },
53
54    /// GroupBy operation.
55    /// Scans `source` (binding columns to `vars`), groups by `keys`, computes `aggregates`
56    /// for each group, and then executes `body` for each group.
57    GroupBy {
58        source: NameId,    // Relation to scan
59        vars: Vec<NameId>, // Variables to bind to source columns
60        keys: Vec<NameId>, // Variables to group by (must be in `vars` or previously bound?)
61        // Typically `keys` are subset of `vars`.
62        aggregates: Vec<Aggregate>,
63        body: Box<Op>,
64    },
65}
66
67#[derive(Debug, Clone, PartialEq)]
68pub struct Aggregate {
69    pub var: NameId,
70    pub func: NameId,
71    pub args: Vec<Operand>,
72}
73
74#[derive(Debug, Clone, PartialEq)]
75pub enum DataSource {
76    /// Scan a relation (iterate over all tuples).
77    /// Binds the variables in `vars` to the columns of the relation.
78    Scan { relation: NameId, vars: Vec<NameId> },
79
80    /// Scan only the "delta" set of a relation (new facts from last iteration).
81    ScanDelta { relation: NameId, vars: Vec<NameId> },
82
83    /// Lookup in an index.
84    /// `col_idx`: The column index to lookup on.
85    /// `key`: The value to look up.
86    /// `vars`: Variables to bind to the *other* columns (or all columns?).
87    /// For simplicity: `vars` maps to the relation columns. The column at `col_idx`
88    /// is already bound (to `key`), but we might re-bind it or check it.
89    IndexLookup {
90        relation: NameId,
91        col_idx: usize,
92        key: Operand,
93        vars: Vec<NameId>,
94    },
95}
96
97#[derive(Debug, Clone, Copy, PartialEq)]
98pub enum CmpOp {
99    Eq,
100    Neq,
101    Lt,
102    Le,
103    Gt,
104    Ge,
105}
106
107#[derive(Debug, Clone, PartialEq)]
108pub enum Condition {
109    /// Comparison of two operands.
110    Cmp {
111        op: CmpOp,
112        left: Operand,
113        right: Operand,
114    },
115    /// Negation check: !exists(...)
116    Negation {
117        relation: NameId,
118        args: Vec<Operand>,
119    },
120    /// Call to a boolean function / predicate (e.g. starts_with).
121    Call {
122        function: NameId,
123        args: Vec<Operand>,
124    },
125}
126
127#[derive(Debug, Clone, PartialEq)]
128pub enum Expr {
129    // Basic value
130    Value(Operand),
131    // Function call (arithmetic or built-in)
132    Call {
133        function: NameId,
134        args: Vec<Operand>,
135    },
136}
137
138#[derive(Debug, Clone, PartialEq)]
139pub enum Operand {
140    Var(NameId),
141    Const(Constant),
142}
143
144#[derive(Clone, Debug, PartialEq)]
145pub enum Constant {
146    Number(i64),
147    Float(f64),
148    String(StringId),
149    Name(NameId),
150    Time(i64),
151    Duration(i64),
152}