lmntalc/
ir.rs

1use std::fmt::Display;
2
3use crate::{
4    frontend::token::Operator,
5    model::{guard::ProcessConstraint, Data},
6};
7
8use owo_colors::OwoColorize;
9
10/// Basic operations of LMNtal
11#[derive(Debug, Clone)]
12pub enum LMNtalIR {
13    /// Create a new atom with specified name and arity
14    CreateAtom {
15        id: usize,
16        name: String,
17        arity: usize,
18        data: Data,
19    },
20    /// Remove an atom with specified `id`
21    ///
22    /// Since it will be only used for in rule,
23    /// the `id` will be the order of the pattern atom in the rule
24    RemoveAtom {
25        id: usize,
26    },
27    /// Remove an atom at specified `port` of atom with specified `id`
28    RemoveAtomAt {
29        id: usize,
30        port: usize,
31    },
32    /// Clone an atom from specified `from` atom with specified `id`
33    CloneAtom {
34        id: usize,
35        from_id: usize,
36        from_port: usize,
37    },
38
39    /// Link atoms with specified ports
40    Link {
41        src: VarSource,
42        dst: VarSource,
43    },
44    /// Link the atom `dst`'s port `dst_port` to the **atom linked to** `src`'s port `src_port`
45    Relink {
46        src: usize,
47        src_port: usize,
48        dst: VarSource,
49    },
50
51    /// Create a new hyperlink with specified name
52    ///
53    /// There is no explicit arity for hyperlink, since it is not fixed
54    CreateHyperlink {
55        id: usize,
56        name: String,
57    },
58    /// Add an atom to a hyperlink
59    LinkToHyperlink {
60        atom: VarSource,
61        hyperlink: VarSource,
62    },
63    /// Remove an atom from a hyperlink
64    RemoveFromHyperlink {
65        atom: VarSource,
66        hyperlink: VarSource,
67    },
68    /// Fuse hyperlink `from` into hyperlink `into`, and remove `from`
69    ///
70    /// i.e. `into` will be the new hyperlink with union of atoms in `into` and `from`
71    FuseHyperlink {
72        into: VarSource,
73        from: VarSource,
74    },
75
76    /// Find atoms with specified name and arity
77    ///
78    /// This will be translated into a range-based for loop since there may be multiple atoms meet the requirement
79    FindAtom {
80        id: usize,
81        name: String,
82        arity: usize,
83    },
84    /// Get the atom at specified `port` of atom with specified `id`
85    GetAtomAtPort {
86        id: usize,
87        from: usize,
88        port: usize,
89        name: String,
90        arity: usize,
91    },
92    /// Get the hyperlink at specified `port` of atom with specified `id`
93    GetHyperlinkAtPort {
94        id: usize,
95        from: usize,
96        port: usize,
97    },
98    /// Check if atoms (or hyperlinks) at id's port are equal
99    AtomEqualityIdPort {
100        /// List of atoms and their ports
101        id_port_list: Vec<(usize, usize)>,
102        /// Whether the atoms are equal or not
103        eq: bool,
104    },
105    /// Check if atoms (or hyperlinks) are equal
106    AtomEquality {
107        /// List of atoms and their ports
108        id_list: Vec<usize>,
109        /// Whether the atoms are equal or not
110        eq: bool,
111        /// Whether they are hyperlinks or atoms
112        hyperlinks: bool,
113    },
114    /// Check the type of an atom at atom `id`'s `port`
115    CheckType {
116        id: usize,
117        port: usize,
118        ty: ProcessConstraint,
119    },
120    /// Check the value using specified operation
121    CheckValue(Operation),
122    /// Define a temporary variable using specified operation with specified name and type
123    DefineTempVar {
124        id: usize,
125        name: String,
126        ty: ProcessConstraint,
127        op: Operation,
128    },
129    Unify {
130        into: VarSource,
131        from: VarSource,
132    },
133}
134
135impl Display for LMNtalIR {
136    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
137        match self {
138            LMNtalIR::CreateAtom {
139                id,
140                name,
141                arity,
142                data,
143            } => {
144                write!(
145                    f,
146                    "create atom at {} with name: {} arity: {} data: {}",
147                    id.underline().bold(),
148                    name,
149                    arity,
150                    data
151                )
152            }
153            LMNtalIR::RemoveAtom { id } => write!(f, "remove atom at {}", id.underline().bold()),
154            LMNtalIR::CloneAtom {
155                id,
156                from_id,
157                from_port,
158            } => {
159                write!(
160                    f,
161                    "clone atom into {} from {} port {} ",
162                    id.underline().bold(),
163                    from_id,
164                    from_port
165                )
166            }
167            LMNtalIR::Link { src, dst } => write!(f, "link {} with {}", src, dst,),
168            LMNtalIR::Relink { src, src_port, dst } => {
169                write!(f, "relink {} port {} with {}", src, src_port, dst)
170            }
171            LMNtalIR::FindAtom { id, name, arity } => {
172                write!(
173                    f,
174                    "find_atom into {} with name: {} arity: {}",
175                    id.underline().bold(),
176                    name,
177                    arity
178                )
179            }
180            LMNtalIR::GetAtomAtPort {
181                id,
182                from,
183                port,
184                name,
185                arity,
186            } => write!(
187                f,
188                "get atom into {} from {} port {} with name: {} arity: {}",
189                id.underline().bold(),
190                from.underline().bold(),
191                port,
192                name,
193                arity
194            ),
195            LMNtalIR::GetHyperlinkAtPort { id, from, port } => write!(
196                f,
197                "get hyperlink into {} from {} port {}",
198                id.underline().bold(),
199                from.underline().bold(),
200                port,
201            ),
202            LMNtalIR::AtomEqualityIdPort { id_port_list, eq } => {
203                let predicate = if *eq { "are" } else { "are not" };
204                write!(f, "atoms {} equal:\n\t\t", predicate)?;
205                for (id, port) in id_port_list {
206                    write!(f, "at {} port {},", id.underline().bold(), port)?;
207                }
208                Ok(())
209            }
210            LMNtalIR::AtomEquality {
211                id_list,
212                eq,
213                hyperlinks,
214            } => {
215                let content = if *hyperlinks { "hyperlinks" } else { "atoms" };
216                let predicate = if *eq { "are" } else { "are not" };
217                write!(f, "{} {} equal:\n\t\t", content, predicate)?;
218                for id in id_list {
219                    write!(f, "at {},", id.underline().bold())?;
220                }
221                Ok(())
222            }
223            LMNtalIR::CheckType { id, port, ty } => write!(
224                f,
225                "check type at {} port {} is {}",
226                id.underline().bold(),
227                port,
228                ty
229            ),
230            LMNtalIR::CheckValue(op) => write!(f, "check if {}", op),
231            LMNtalIR::DefineTempVar { id, name, ty, op } => {
232                write!(
233                    f,
234                    "define a temp var at {} {} {} {}",
235                    id.underline().bold(),
236                    name,
237                    ty,
238                    op
239                )
240            }
241            LMNtalIR::RemoveAtomAt { id, port } => {
242                write!(f, "remove atom at {} port {}", id.underline().bold(), port)
243            }
244            LMNtalIR::CreateHyperlink { id, name } => {
245                write!(
246                    f,
247                    "create hyperlink at {} with name: {}",
248                    id.underline().bold(),
249                    name,
250                )
251            }
252            LMNtalIR::LinkToHyperlink { atom, hyperlink } => {
253                write!(f, "add atom {} to hyperlink {}", atom, hyperlink)
254            }
255            LMNtalIR::RemoveFromHyperlink { atom, hyperlink } => {
256                write!(f, "remove atom {} from hyperlink {}", atom, hyperlink)
257            }
258            LMNtalIR::FuseHyperlink { into, from } => {
259                write!(f, "fuse hyperlink {} into hyperlink {}", from, into)
260            }
261            LMNtalIR::Unify { into, from } => {
262                write!(f, "unify {} with {}", from, into)
263            }
264        }
265    }
266}
267
268#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
269pub enum VarSource {
270    Head(usize, usize),
271    Variable(usize),
272    Body(usize, usize),
273}
274
275impl VarSource {
276    pub fn id(&self) -> usize {
277        match self {
278            VarSource::Head(id, _) => *id,
279            VarSource::Variable(id) => *id,
280            VarSource::Body(id, _) => *id,
281        }
282    }
283}
284
285impl Display for VarSource {
286    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
287        match self {
288            VarSource::Head(id, port) => write!(f, "head {} port {}", id.underline().bold(), port),
289            VarSource::Variable(id) => write!(f, "temp {}", id.underline().bold()),
290            VarSource::Body(id, port) => write!(f, "body {} port {}", id.underline().bold(), port),
291        }
292    }
293}
294
295#[derive(Debug, Clone)]
296pub enum Operation {
297    Literal(Literal),
298    Variable {
299        source: VarSource,
300        ty_: ProcessConstraint,
301    },
302    BinaryOP {
303        op: BinaryOperator,
304        lhs: Box<Operation>,
305        rhs: Box<Operation>,
306    },
307    UnaryOP {
308        op: UnaryOperator,
309        operand: Box<Operation>,
310    },
311    FunctionCall {
312        name: String,
313        args: Vec<Operation>,
314        ty_: ProcessConstraint,
315    },
316}
317
318impl Display for Operation {
319    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
320        match self {
321            Operation::Literal(l) => write!(f, "{}", l),
322            Operation::Variable { source, ty_ } => match source {
323                VarSource::Head(id, port) => {
324                    write!(
325                        f,
326                        "(var at {} port {} with type {})",
327                        id.underline().bold(),
328                        port,
329                        ty_
330                    )
331                }
332                VarSource::Variable(id) => {
333                    write!(f, "(var at {} with type {})", id.underline().bold(), ty_)
334                }
335                VarSource::Body(id, port) => {
336                    write!(
337                        f,
338                        "(var at {} port {} with type {})",
339                        id.underline().bold(),
340                        port,
341                        ty_
342                    )
343                }
344            },
345            Operation::BinaryOP { op, lhs, rhs } => write!(f, "({} {} {})", lhs, op, rhs),
346            Operation::UnaryOP { op, operand } => write!(f, "({} {})", op, operand),
347            Operation::FunctionCall { name, args, .. } => {
348                write!(
349                    f,
350                    "{}({})",
351                    name,
352                    args.iter()
353                        .map(|a| format!("{}", a))
354                        .collect::<Vec<String>>()
355                        .join(", ")
356                )
357            }
358        }
359    }
360}
361
362#[derive(Debug, Clone, PartialEq)]
363pub enum Literal {
364    Int(i64),
365    Float(f64),
366    Char(char),
367    String(String),
368}
369
370impl Display for Literal {
371    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
372        match self {
373            Literal::Int(i) => write!(f, "{}", i),
374            Literal::Float(fl) => write!(f, "{}", fl),
375            Literal::Char(c) => write!(f, "{}", c),
376            Literal::String(s) => write!(f, "{}", s),
377        }
378    }
379}
380
381#[derive(Debug, Clone, Copy)]
382pub enum BinaryOperator {
383    Add,
384    Sub,
385    Mul,
386    Div,
387    Mod,
388    Pow,
389    Eq,
390    Ne,
391    Lt,
392    Le,
393    Gt,
394    Ge,
395}
396
397impl Display for BinaryOperator {
398    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
399        let s = match self {
400            BinaryOperator::Add => "+",
401            BinaryOperator::Sub => "-",
402            BinaryOperator::Mul => "*",
403            BinaryOperator::Div => "/",
404            BinaryOperator::Mod => "%",
405            BinaryOperator::Pow => "**",
406            BinaryOperator::Eq => "==",
407            BinaryOperator::Ne => "!=",
408            BinaryOperator::Lt => "<",
409            BinaryOperator::Le => "<=",
410            BinaryOperator::Gt => ">",
411            BinaryOperator::Ge => ">=",
412        };
413        write!(f, "{}", s)
414    }
415}
416
417impl From<&Operator> for BinaryOperator {
418    fn from(value: &Operator) -> Self {
419        match value {
420            Operator::IAdd | Operator::FAdd => Self::Add,
421            Operator::ISub | Operator::FSub => Self::Sub,
422            Operator::IMul | Operator::FMul => Self::Mul,
423            Operator::IDiv | Operator::FDiv => Self::Div,
424            Operator::IMod => Self::Mod,
425            Operator::IPow => Self::Pow,
426            Operator::IEq | Operator::FEq | Operator::UnaryEq | Operator::GroundEq => Self::Eq,
427            Operator::INe | Operator::FNe | Operator::UnaryNe | Operator::GroundNe => Self::Ne,
428            Operator::ILt | Operator::FLt => Self::Lt,
429            Operator::ILe | Operator::FLe => Self::Le,
430            Operator::IGt | Operator::FGt => Self::Gt,
431            Operator::IGe | Operator::FGe => Self::Ge,
432            Operator::Equal => todo!(),
433            Operator::HyperlinkFuse => todo!(),
434            Operator::HyperlinkUnify => todo!(),
435            Operator::Negative => todo!(),
436            Operator::Question => todo!(),
437            Operator::DoubleColon => todo!(),
438            Operator::LogicalAnd => todo!(),
439            Operator::LogicalOr => todo!(),
440            Operator::LogicalNot => todo!(),
441            Operator::LogicalXor => todo!(),
442            Operator::LogicalShift => todo!(),
443            Operator::ArithmeticShift => todo!(),
444        }
445    }
446}
447
448#[derive(Debug, Clone, Copy)]
449pub enum UnaryOperator {
450    Not,
451    Neg,
452}
453
454impl Display for UnaryOperator {
455    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
456        let s = match self {
457            UnaryOperator::Not => "!",
458            UnaryOperator::Neg => "-",
459        };
460        write!(f, "{}", s)
461    }
462}