xee_ir/
binding.rs

1use xee_xpath_ast::{ast::Span, span::Spanned};
2
3use crate::{ir, Variables};
4
5/// A binding consists of a unique variable name and an expression.
6#[derive(Debug, Clone)]
7pub struct Binding {
8    name: ir::Name,
9    expr: ir::Expr,
10    span: Span,
11}
12
13impl Binding {
14    #[inline]
15    pub fn new(name: ir::Name, expr: ir::Expr, span: Span) -> Self {
16        Self { name, expr, span }
17    }
18}
19
20#[derive(Debug, Clone)]
21pub struct Bindings {
22    bindings: Vec<Binding>,
23}
24
25impl Bindings {
26    pub fn new(binding: Binding) -> Self {
27        Self {
28            bindings: vec![binding],
29        }
30    }
31
32    pub fn empty() -> Self {
33        Self {
34            bindings: Vec::new(),
35        }
36    }
37
38    /// Create an atom
39    /// Takes the last added binding
40    /// If it's already an atom, return it, and pops it from the bindings.
41    /// If it's not atom, create a variable based on its name and
42    /// return that as an atom.
43    pub fn atom(&mut self) -> ir::AtomS {
44        let last = self.bindings.last().unwrap();
45        let (want_pop, atom) = match &last.expr {
46            ir::Expr::Atom(atom) => (true, atom.clone()),
47            _ => (
48                false,
49                Spanned::new(ir::Atom::Variable(last.name.clone()), last.span),
50            ),
51        };
52        if want_pop {
53            self.bindings.pop();
54        }
55        atom
56    }
57
58    /// Given bindings, return a let expression.
59    /// This takes all the bindings and wraps it in a let expression.
60    pub fn expr(&self) -> ir::ExprS {
61        let last_binding = self.bindings.last().unwrap();
62        let bindings = &self.bindings[..self.bindings.len() - 1];
63        let expr = last_binding.expr.clone();
64        Spanned::new(
65            bindings.iter().rev().fold(expr, |expr, binding| {
66                ir::Expr::Let(ir::Let {
67                    name: binding.name.clone(),
68                    var_expr: Box::new(Spanned::new(binding.expr.clone(), binding.span)),
69                    return_expr: Box::new(Spanned::new(expr, last_binding.span)),
70                })
71            }),
72            last_binding.span,
73        )
74    }
75
76    pub fn atom_bindings(mut self) -> (ir::AtomS, Self) {
77        let atom = self.atom();
78        (atom, self)
79    }
80
81    pub fn bind_expr(&self, variables: &mut Variables, expr: ir::ExprS) -> Self {
82        let binding = variables.new_binding(expr.value, expr.span);
83        self.bind(binding)
84    }
85
86    pub fn bind_expr_no_span(&self, variables: &mut Variables, expr: ir::Expr) -> Self {
87        let binding = variables.new_binding(expr, (0..0).into());
88        self.bind(binding)
89    }
90
91    /// Create a new Bindings by adding the existing binding to it
92    pub fn bind(&self, binding: Binding) -> Self {
93        let mut bindings = self.clone();
94        bindings.bindings.push(binding);
95        bindings
96    }
97
98    /// Concatenate one bindings object with another, creating a new one.
99    pub fn concat(&self, bindings: Bindings) -> Self {
100        let mut result = self.clone();
101        result.bindings.extend(bindings.bindings);
102        result
103    }
104}