1
use std::fmt;
2

            
3
use ahash::HashMap;
4
use ahash::HashMapExt;
5
use merc_aterm::ATermRef;
6
use merc_aterm::Markable;
7
use merc_aterm::Protected;
8
use merc_aterm::SymbolRef;
9
use merc_aterm::Term;
10
use merc_aterm::Transmutable;
11
use merc_aterm::storage::Marker;
12
use merc_data::DataApplication;
13
use merc_data::DataExpression;
14
use merc_data::DataExpressionRef;
15
use merc_data::DataFunctionSymbolRef;
16
use merc_data::DataVariable;
17
use merc_data::DataVariableRef;
18
use merc_data::is_data_machine_number;
19
use merc_data::is_data_variable;
20
use merc_utilities::debug_trace;
21

            
22
use crate::Rule;
23
use crate::utilities::InnermostStack;
24

            
25
use super::DataPosition;
26
use super::DataPositionIterator;
27

            
28
/// A stack used to represent a term with free variables that can be constructed
29
/// efficiently.
30
///
31
/// It stores as much as possible in the term pool. Due to variables it cannot
32
/// be fully compressed. For variables it stores the position in the lhs of a
33
/// rewrite rule where the concrete term can be found that will replace the
34
/// variable.
35
///
36
#[derive(Hash, Debug, PartialEq, Eq, PartialOrd, Ord)]
37
pub struct TermStack {
38
    /// The innermost rewrite stack for the right hand side and the positions that must be added to the stack.
39
    pub innermost_stack: Protected<Vec<Config<'static>>>,
40
    /// The variables of the left-hand side that must be placed at certain places in the stack.
41
    pub variables: Vec<(DataPosition, usize)>,
42
    /// The number of elements that must be reserved on the innermost stack.
43
    pub stack_size: usize,
44
}
45

            
46
#[derive(Hash, Eq, PartialEq, Ord, PartialOrd, Debug)]
47
pub enum Config<'a> {
48
    /// Rewrite the top of the stack and put result at the given index.
49
    Rewrite(usize),
50
    /// Constructs function symbol with given arity at the given index.
51
    Construct(DataFunctionSymbolRef<'a>, usize, usize),
52
    /// A concrete term to be placed at the current position in the stack.
53
    Term(DataExpressionRef<'a>, usize),
54
    /// Yields the given index as returned term.
55
    Return(),
56
}
57

            
58
impl Markable for Config<'_> {
59
5981181
    fn mark(&self, marker: &mut Marker<'_>) {
60
5981181
        if let Config::Construct(t, _, _) = self {
61
5980581
            t.mark(marker);
62
5980581
        }
63
5981181
    }
64

            
65
620563265
    fn contains_term(&self, term: &ATermRef<'_>) -> bool {
66
620563265
        if let Config::Construct(t, _, _) = self {
67
576216089
            t.contains_term(term)
68
        } else {
69
44347176
            false
70
        }
71
620563265
    }
72

            
73
    fn contains_symbol(&self, symbol: &SymbolRef<'_>) -> bool {
74
        if let Config::Construct(t, _, _) = self {
75
            t.contains_symbol(symbol)
76
        } else {
77
            false
78
        }
79
    }
80

            
81
    fn len(&self) -> usize {
82
        if let Config::Construct(_, _, _) = self { 1 } else { 0 }
83
    }
84
}
85

            
86
// SAFETY: `Config` only borrows the term pool through its `DataFunctionSymbolRef`
87
// / `DataExpressionRef` fields, which are themselves lifetime-erasable handles
88
// into the global term pool. Transmuting only changes the lifetime parameter, so
89
// the layout is identical.
90
unsafe impl Transmutable for Config<'static> {
91
    type Target<'a> = Config<'a>;
92

            
93
    unsafe fn transmute_lifetime<'a>(&'_ self) -> &'a Self::Target<'a> {
94
        // SAFETY: see the trait impl comment above; the caller upholds that 'a does not
95
        // outlive the borrow of `self`.
96
        unsafe { std::mem::transmute::<&Self, &'a Config>(self) }
97
    }
98

            
99
    unsafe fn transmute_lifetime_mut<'a>(&'_ mut self) -> &'a mut Self::Target<'a> {
100
        // SAFETY: see the trait impl comment above; the caller upholds that 'a does not
101
        // outlive the borrow of `self`.
102
        unsafe { std::mem::transmute::<&mut Self, &'a mut Config>(self) }
103
    }
104
}
105

            
106
impl fmt::Display for Config<'_> {
107
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108
        match self {
109
            Config::Rewrite(result) => write!(f, "Rewrite({result})"),
110
            Config::Construct(symbol, arity, result) => {
111
                write!(f, "Construct({symbol}, {arity}, {result})")
112
            }
113
            Config::Term(term, result) => {
114
                write!(f, "Term({term}, {result})")
115
            }
116
            Config::Return() => write!(f, "Return()"),
117
        }
118
    }
119
}
120

            
121
impl TermStack {
122
    /// Construct a new right-hand stack for a given equation/rewrite rule.
123
4277
    pub fn new(rule: &Rule) -> TermStack {
124
4277
        Self::from_term(&rule.rhs.copy(), &create_var_map(&rule.lhs))
125
4277
    }
126

            
127
    /// Construct a term stack from a data expression where variables are taken from a specific position of the left hand side.
128
78568
    pub fn from_term(term: &DataExpressionRef, var_map: &HashMap<DataVariable, DataPosition>) -> TermStack {
129
        // Compute the extra information for the InnermostRewriter.
130
78568
        let mut innermost_stack: Protected<Vec<Config>> = Protected::new(vec![]);
131
78568
        let mut variables = vec![];
132
78568
        let mut stack_size = 0;
133

            
134
273776
        for (term, _position) in DataPositionIterator::new(term.copy()) {
135
273776
            if is_data_variable(&term) {
136
63582
                let variable: DataVariableRef<'_> = term.into();
137
63582
                variables.push((
138
63582
                    var_map
139
63582
                        .get(&variable.protect())
140
63582
                        .expect("All variables in the right hand side must occur in the left hand side")
141
63582
                        .clone(),
142
63582
                    stack_size,
143
63582
                ));
144
63582
                stack_size += 1;
145
210194
            } else if is_data_machine_number(&term) {
146
                // Skip SortId(@NoValue) and OpId
147
210194
            } else {
148
210194
                let arity = term.data_arguments().len();
149
210194
                let mut write = innermost_stack.write();
150
210194
                write.push(Config::Construct(term.data_function_symbol(), arity, stack_size));
151
210194
                stack_size += 1;
152
210194
            }
153
        }
154

            
155
78568
        TermStack {
156
78568
            innermost_stack,
157
78568
            stack_size,
158
78568
            variables,
159
78568
        }
160
78568
    }
161

            
162
    // See [evaluate_with]
163
4052
    pub fn evaluate<'a, 'b, T: Term<'a, 'b>>(&self, term: &'b T) -> DataExpression {
164
4052
        let mut builder = TermStackBuilder::new();
165
4052
        self.evaluate_with(term, &mut builder)
166
4052
    }
167

            
168
    /// Evaluate the rhs stack for the given term and returns the result.
169
4862198
    pub fn evaluate_with<'a, 'b, T: Term<'a, 'b>>(
170
4862198
        &self,
171
4862198
        term: &'b T,
172
4862198
        builder: &mut TermStackBuilder,
173
4862198
    ) -> DataExpression {
174
4862198
        let stack = &mut builder.stack;
175
4862198
        {
176
4862198
            let mut write = stack.terms.write();
177
4862198
            write.clear();
178
4862198
            write.push(None);
179
4862198
        }
180

            
181
4862198
        InnermostStack::integrate(
182
4862198
            &mut stack.configs.write(),
183
4862198
            &mut stack.terms.write(),
184
4862198
            self,
185
4862198
            &DataExpressionRef::from(term.copy()),
186
            0,
187
        );
188

            
189
        loop {
190
10198299
            debug_trace!("{}", stack);
191

            
192
10198299
            let mut write_configs = stack.configs.write();
193
10198299
            if let Some(config) = write_configs.pop() {
194
5336101
                match config {
195
5336101
                    Config::Construct(symbol, arity, index) => {
196
                        // Take the last arity arguments.
197
5336101
                        let mut write_terms = stack.terms.write();
198
5336101
                        let length = write_terms.len();
199

            
200
5336101
                        let arguments = &write_terms[length - arity..];
201

            
202
5336101
                        let term: DataExpression = if arguments.is_empty() {
203
1132403
                            symbol.protect().into()
204
                        } else {
205
4203698
                            DataApplication::with_iter(&symbol.copy(), arguments.len(), arguments.iter().flatten())
206
4203698
                                .into()
207
                        };
208

            
209
                        // Add the term on the stack.
210
5336101
                        write_terms.drain(length - arity..);
211
                        // Safety: t is stored in the container on the next line.
212
5336101
                        let t = unsafe { write_terms.protect(&term) };
213
5336101
                        write_terms[index] = Some(t.into());
214
                    }
215
                    Config::Term(term, index) => {
216
                        let mut write_terms = stack.terms.write();
217
                        // Safety: t is stored in the container on the next line.
218
                        let t = unsafe { write_terms.protect(&term) };
219
                        write_terms[index] = Some(t.into());
220
                    }
221
                    Config::Rewrite(_) => {
222
                        unreachable!("This case should not happen");
223
                    }
224
                    Config::Return() => {
225
                        unreachable!("This case should not happen");
226
                    }
227
                }
228
            } else {
229
4862198
                break;
230
            }
231
        }
232

            
233
4862198
        debug_assert!(
234
4862198
            stack.terms.read().len() == 1,
235
            "Expect exactly one term on the result stack"
236
        );
237

            
238
4862198
        let mut write_terms = stack.terms.write();
239

            
240
4862198
        write_terms
241
4862198
            .pop()
242
4862198
            .expect("The result should be the last element on the stack")
243
4862198
            .expect("The result should be Some")
244
4862198
            .protect()
245
4862198
    }
246

            
247
    /// Used to check if a subterm is duplicated, for example "times(s(x), y) =
248
    /// plus(y, times(x,y))" is duplicating.
249
42418
    pub(crate) fn contains_duplicate_var_references(&self) -> bool {
250
42418
        let mut variables: Vec<&DataPosition> = self.variables.iter().map(|(v, _)| v).collect();
251

            
252
        // Check if there are duplicates.
253
42418
        variables.sort_unstable();
254
42418
        let len = variables.len();
255
42418
        variables.dedup();
256

            
257
42418
        len != variables.len()
258
42418
    }
259
}
260

            
261
impl Clone for TermStack {
262
    fn clone(&self) -> Self {
263
        // TODO: It would make sense if Protected could implement Clone.
264
        let mut innermost_stack: Protected<Vec<Config>> = Protected::new(vec![]);
265

            
266
        let read = self.innermost_stack.read();
267
        let mut write = innermost_stack.write();
268
        for t in read.iter() {
269
            match t {
270
                Config::Rewrite(x) => write.push(Config::Rewrite(*x)),
271
                Config::Construct(f, x, y) => {
272
                    write.push(Config::Construct(f.copy(), *x, *y));
273
                }
274
                Config::Term(t, y) => {
275
                    write.push(Config::Term(t.copy(), *y));
276
                }
277
                Config::Return() => write.push(Config::Return()),
278
            }
279
        }
280
        drop(write);
281

            
282
        Self {
283
            variables: self.variables.clone(),
284
            stack_size: self.stack_size,
285
            innermost_stack,
286
        }
287
    }
288
}
289

            
290
pub struct TermStackBuilder {
291
    stack: InnermostStack,
292
}
293

            
294
impl TermStackBuilder {
295
4220
    pub fn new() -> Self {
296
4220
        Self {
297
4220
            stack: InnermostStack::default(),
298
4220
        }
299
4220
    }
300
}
301

            
302
impl Default for TermStackBuilder {
303
    fn default() -> Self {
304
        Self::new()
305
    }
306
}
307

            
308
/// Create a mapping of variables to their position in the given term
309
93387
pub fn create_var_map(t: &DataExpression) -> HashMap<DataVariable, DataPosition> {
310
93387
    let mut result = HashMap::new();
311

            
312
197390
    for (term, position) in DataPositionIterator::new(t.copy()) {
313
197390
        if is_data_variable(&term) {
314
86608
            result.insert(term.protect().into(), position.clone());
315
110782
        }
316
    }
317

            
318
93387
    result
319
93387
}
320

            
321
#[cfg(test)]
322
mod tests {
323
    use ahash::AHashSet;
324
    use ahash::HashMap;
325
    use ahash::HashMapExt;
326
    use merc_aterm::Protected;
327
    use merc_data::DataExpression;
328
    use merc_data::DataFunctionSymbol;
329
    use merc_data::DataVariable;
330
    use merc_utilities::test_logger;
331

            
332
    use crate::test_utility::create_rewrite_rule;
333
    use crate::utilities::Config;
334
    use crate::utilities::DataPosition;
335
    use crate::utilities::TermStack;
336
    use crate::utilities::create_var_map;
337

            
338
    use test_log::test;
339

            
340
    #[test]
341
1
    fn test_rhs_stack() {
342
1
        let rhs_stack = TermStack::new(&create_rewrite_rule("fact(s(N))", "times(s(N), fact(N))", &["N"]).unwrap());
343
1
        let mut expected = Protected::new(vec![]);
344

            
345
1
        let t1 = DataFunctionSymbol::new("times");
346
1
        let t2 = DataFunctionSymbol::new("s");
347
1
        let t3 = DataFunctionSymbol::new("fact");
348

            
349
1
        let mut write = expected.write();
350
1
        write.push(Config::Construct(t1.copy(), 2, 0));
351
1
        write.push(Config::Construct(t2.copy(), 1, 1));
352
1
        write.push(Config::Construct(t3.copy(), 1, 2));
353
1
        drop(write);
354

            
355
        // Check if the resulting construction succeeded.
356
1
        assert_eq!(
357
            rhs_stack.innermost_stack, expected,
358
            "The resulting config stack is not as expected"
359
        );
360

            
361
1
        assert_eq!(rhs_stack.stack_size, 5, "The stack size does not match");
362

            
363
        // Test the evaluation
364
1
        let lhs = DataExpression::from_string("fact(s(a))").unwrap();
365
1
        let rhs = DataExpression::from_string("times(s(a), fact(a))").unwrap();
366

            
367
1
        assert_eq!(
368
1
            rhs_stack.evaluate(&lhs),
369
            rhs,
370
            "The rhs stack does not evaluate to the expected term"
371
        );
372
1
    }
373

            
374
    #[test]
375
1
    fn test_rhs_stack_variable() {
376
1
        let rhs = TermStack::new(&create_rewrite_rule("f(x)", "x", &["x"]).unwrap());
377

            
378
        // Check if the resulting construction succeeded.
379
1
        assert!(
380
1
            rhs.innermost_stack.read().is_empty(),
381
            "The resulting config stack is not as expected"
382
        );
383

            
384
1
        assert_eq!(rhs.stack_size, 1, "The stack size does not match");
385
1
    }
386

            
387
    #[test]
388
1
    fn test_evaluation() {
389
1
        test_logger();
390

            
391
1
        let rhs = DataExpression::from_string_untyped("f(f(a,a),x)", &AHashSet::from([String::from("x")])).unwrap();
392
1
        let lhs = DataExpression::from_string("g(b)").unwrap();
393

            
394
        // Make a variable map with only x@1.
395
1
        let mut map = HashMap::new();
396
1
        map.insert(DataVariable::new("x"), DataPosition::new(&[1]));
397

            
398
1
        let sctt = TermStack::from_term(&rhs.copy(), &map);
399

            
400
1
        let expected = DataExpression::from_string("f(f(a,a),b)").unwrap();
401

            
402
1
        assert_eq!(sctt.evaluate(&lhs), expected);
403
1
    }
404

            
405
    #[test]
406
1
    fn test_create_varmap() {
407
1
        let t = DataExpression::from_string_untyped("f(x,x)", &AHashSet::from([String::from("x")])).unwrap();
408
1
        let x = DataVariable::new("x");
409

            
410
1
        let map = create_var_map(&t);
411
1
        assert!(map.contains_key(&x));
412
1
    }
413

            
414
    #[test]
415
1
    fn test_is_duplicating() {
416
1
        let rhs = DataExpression::from_string_untyped("f(x,x)", &AHashSet::from([String::from("x")])).unwrap();
417

            
418
        // Make a variable map with only x@1.
419
1
        let mut map = HashMap::new();
420
1
        map.insert(DataVariable::new("x"), DataPosition::new(&[1]));
421

            
422
1
        let sctt = TermStack::from_term(&rhs.copy(), &map);
423
1
        assert!(sctt.contains_duplicate_var_references(), "This sctt is duplicating");
424
1
    }
425
}