smt_scope/parsers/z3/
parse.rs

1use core::num::{NonZeroU32, NonZeroUsize};
2
3use num::Num;
4
5use crate::{
6    items::*,
7    parsers::z3::{VersionInfo, Z3LogParser},
8    BigRational, BoxSlice, Error as E, IString, NonMaxU32, Result, StringTable,
9};
10
11use super::{inter_line::LineKind, smt2::EventLog, terms::Terms, Z3Parser};
12
13impl Default for Z3Parser {
14    fn default() -> Self {
15        let mut strings = StringTable::with_hasher(fxhash::FxBuildHasher::default());
16        Self {
17            version_info: VersionInfo::default(),
18            push_count: 0,
19            terms: Terms::default(),
20            synth_terms: Default::default(),
21            quantifiers: Default::default(),
22            insts: Default::default(),
23            // ts: Default::default(),
24            egraph: Default::default(),
25            stack: Default::default(),
26            lits: Default::default(),
27            events: EventLog::new(&mut strings),
28            comm: Default::default(),
29            strings,
30        }
31    }
32}
33
34impl Z3Parser {
35    pub(super) fn incremental_mode(&self) -> bool {
36        self.push_count > 0
37    }
38
39    fn parse_new_full_id(&mut self, id: Option<&str>) -> Result<TermId> {
40        let full_id = id.ok_or(E::UnexpectedNewline)?;
41        TermId::parse(&mut self.strings, full_id)
42    }
43
44    fn parse_existing_app(&mut self, id: &str) -> Result<TermIdx> {
45        self.terms
46            .app_terms
47            .parse_existing_id(&mut self.strings, id)
48    }
49
50    fn parse_existing_proof(&mut self, id: &str) -> Result<ProofIdx> {
51        self.terms
52            .proof_terms
53            .parse_existing_id(&mut self.strings, id)
54    }
55
56    fn parse_existing_enode(&mut self, id: &str) -> Result<ENodeIdx> {
57        let idx = self.parse_existing_app(id)?;
58        self.get_existing_enode(idx)
59    }
60
61    fn get_existing_enode(&mut self, idx: TermIdx) -> Result<ENodeIdx> {
62        let res = self.egraph.get_enode(idx, &self.stack);
63        let can_error =
64            self.version_info.is_ge_version(4, 8, 9) && self.version_info.is_le_version(4, 11, 2);
65        if can_error && res.is_err() {
66            // Very rarely in v4.8.17 & v4.11.2, an `[attach-enode]` is not
67            // emitted. Create it here.
68            // TODO: log somewhere when this happens.
69            self.egraph
70                .new_enode(ENodeBlame::Unknown, idx, NonMaxU32::ZERO, &self.stack)?;
71            self.events.new_enode();
72            return self.egraph.get_enode(idx, &self.stack);
73        }
74        res
75    }
76
77    fn new_term(
78        &mut self,
79        id: TermId,
80        kind: TermKind,
81        child_ids: BoxSlice<TermIdx>,
82    ) -> Result<TermIdx> {
83        let term = Term::new(id, kind, child_ids, |tidx| &self[tidx]);
84        self.terms.app_terms.new_term(term)
85    }
86
87    fn parse_z3_generation<'a>(l: &mut impl Iterator<Item = &'a str>) -> Result<Option<NonMaxU32>> {
88        if let Some(gen) = l.next() {
89            let gen = gen.parse::<NonMaxU32>().map_err(E::InvalidGeneration)?;
90            Ok(Some(gen))
91        } else {
92            Ok(None)
93        }
94    }
95
96    fn map<T, U>(l: impl Iterator<Item = T>, f: impl FnMut(T) -> Result<U>) -> Result<BoxSlice<U>> {
97        l.map(f).collect()
98    }
99    fn gobble_var_names_list<'a>(&mut self, l: impl Iterator<Item = &'a str>) -> Result<VarNames> {
100        let mut t = Self::gobble_tuples::<true>(l);
101        // TODO: if the list can be empty then remove the first `?` and
102        // replace with default case.
103        let (first, second) = t.next().ok_or(E::UnexpectedEnd)??;
104        if first.is_empty() {
105            let first = self.mk_string(second);
106            let tuples = t.map(|t| match t? {
107                ("", second) => self.mk_string(second),
108                _ => Err(E::VarNamesListInconsistent),
109            });
110            let types = [first].into_iter().chain(tuples);
111            Ok(VarNames::TypeOnly(types.collect::<Result<_>>()?))
112        } else {
113            fn strip_bars(
114                strings: &mut StringTable,
115                (first, second): (&str, &str),
116            ) -> Result<(IString, IString)> {
117                let first = first
118                    .strip_prefix('|')
119                    .ok_or(E::VarNamesNoBar)?
120                    .strip_suffix('|')
121                    .ok_or(E::VarNamesNoBar)?;
122                let second = second
123                    .strip_prefix('|')
124                    .ok_or(E::VarNamesNoBar)?
125                    .strip_suffix('|')
126                    .ok_or(E::VarNamesNoBar)?;
127                Ok((
128                    IString(strings.get_or_intern(first)),
129                    IString(strings.get_or_intern(second)),
130                ))
131            }
132            let first = strip_bars(&mut self.strings, (first, second));
133            let tuples = t.map(|t| strip_bars(&mut self.strings, t?));
134            let names_and_types = [first].into_iter().chain(tuples);
135            Ok(VarNames::NameAndType(
136                names_and_types.collect::<Result<_>>()?,
137            ))
138        }
139    }
140    /// Gobble tuples with any of the following forms (`A` and `B` can be empty):
141    ///  - `(A;B)`
142    ///  - `(A B)`
143    ///  - `(A ; B)`
144    ///
145    /// The resulting iterator will contain `None` for any tuples which it failed to parse.
146    /// If `FORMS_EQUAL` is true, then it will return `None` for any tuples which have a different
147    /// form to the first tuple.
148    fn gobble_tuples<'a, const FORMS_EQUAL: bool>(
149        mut l: impl Iterator<Item = &'a str>,
150    ) -> impl Iterator<Item = Result<(&'a str, &'a str)>> {
151        let mut spaces = None;
152        let mut gobble = move || {
153            let Some(first) = l.next() else {
154                return Ok(None);
155            };
156            let (first, second) = if first.ends_with(')') {
157                let spaces = *spaces.get_or_insert(0);
158                if FORMS_EQUAL && spaces != 0 {
159                    return Err(E::UnequalTupleForms(spaces, 0));
160                }
161                let mut l = first.split(';');
162                (
163                    l.next().ok_or(E::UnexpectedNewline)?,
164                    l.next().ok_or(E::UnexpectedNewline)?,
165                )
166            } else {
167                let middle = l.next().ok_or(E::UnexpectedNewline)?;
168                if middle != ";" {
169                    let spaces = *spaces.get_or_insert(1);
170                    if FORMS_EQUAL && spaces != 1 {
171                        return Err(E::UnequalTupleForms(spaces, 1));
172                    }
173                    (first, middle)
174                } else {
175                    let spaces = *spaces.get_or_insert(2);
176                    if FORMS_EQUAL && spaces != 2 {
177                        return Err(E::UnequalTupleForms(spaces, 2));
178                    }
179                    let second = l.next().ok_or(E::UnexpectedNewline)?;
180                    (first, second)
181                }
182            };
183            let t = (
184                first.strip_prefix('(').ok_or(E::TupleMissingParens)?,
185                second.strip_suffix(')').ok_or(E::TupleMissingParens)?,
186            );
187            Ok(Some(t))
188        };
189        let inverted_gobble = move |_| gobble().map_or_else(|err| Some(Err(err)), |ok| ok.map(Ok));
190        std::iter::repeat(()).map_while(inverted_gobble)
191    }
192    fn append_trans_equality_tuples<'a>(
193        &mut self,
194        l: impl Iterator<Item = &'a str>,
195        mut f: impl FnMut((ENodeIdx, ENodeIdx)) -> Result<()>,
196    ) -> Result<()> {
197        for t in Self::gobble_tuples::<true>(l) {
198            let (from, to) = t?;
199            let from = self.parse_existing_enode(from)?;
200            let to = self.parse_existing_enode(to)?;
201            f((from, to))?;
202        }
203        Ok(())
204    }
205
206    /// Create a new iterator which will only consume elements from `l` until
207    /// it finds `end`. The element `end` will also be consumed but no other elements after that will.
208    fn iter_until_eq<'a, 's>(
209        l: &'a mut impl Iterator<Item = &'s str>,
210        end: &'a str,
211    ) -> impl Iterator<Item = &'s str> + 'a {
212        l.take_while(move |elem| *elem != end)
213    }
214    fn expect_completed<'s>(mut l: impl Iterator<Item = &'s str>) -> Result<()> {
215        l.next()
216            .map_or(Ok(()), |more| Err(E::ExpectedNewline(more.to_string())))
217    }
218
219    fn mk_string(&mut self, s: &str) -> Result<IString> {
220        Ok(IString(self.strings.try_get_or_intern(s)?))
221    }
222
223    fn quant_or_lamda(
224        &mut self,
225        full_id: TermId,
226        child_ids: BoxSlice<TermIdx>,
227        num_vars: NonMaxU32,
228        kind: QuantKind,
229    ) -> Result<()> {
230        let qidx = self.quantifiers.next_key();
231        let tidx = self.new_term(full_id, TermKind::Quant(qidx), child_ids)?;
232        let q = Quantifier {
233            num_vars,
234            term: tidx,
235            kind,
236            vars: None,
237        };
238        self.quantifiers.raw.try_reserve(1)?;
239        let qidx2 = self.quantifiers.push_and_get_key(q);
240        debug_assert_eq!(qidx, qidx2);
241        Ok(())
242    }
243
244    fn parse_arith(meaning: &str) -> Result<BigRational> {
245        let (rest, num) = Self::parse_arith_inner(meaning)?;
246        debug_assert!(rest.is_empty());
247        Ok(num.into())
248    }
249    fn parse_arith_inner(meaning: &str) -> Result<(&str, num::BigRational)> {
250        let Some(meaning) = meaning.strip_prefix('(') else {
251            // Find position of not a digit
252            let end = meaning
253                .bytes()
254                .position(|b| !b.is_ascii_digit())
255                .unwrap_or(meaning.len());
256            assert_ne!(end, 0);
257            let value = meaning[..end]
258                .parse::<num::BigUint>()
259                .map_err(E::ParseBigUintError)?;
260            let value = num::BigRational::from(num::BigInt::from(value));
261            return Ok((&meaning[end..], value));
262        };
263        let error = || E::ParseError(meaning.to_owned());
264        let space = meaning.bytes().position(|b| b == b' ').ok_or_else(error)?;
265        let (op, mut rest) = (&meaning[..space], &meaning[space..]);
266        let mut arguments = Vec::new();
267        while let Some(r) = rest.strip_prefix(' ') {
268            let (r, num) = Self::parse_arith_inner(r)?;
269            arguments.push(num);
270            rest = r;
271        }
272        rest = rest.strip_prefix(')').ok_or_else(error)?;
273        match op {
274            "+" => Ok((rest, arguments.into_iter().sum())),
275            "-" if arguments.len() == 1 => Ok((rest, -arguments.into_iter().next().unwrap())),
276            "-" if arguments.len() == 2 => {
277                let mut args = arguments.into_iter();
278                Ok((rest, args.next().unwrap() - args.next().unwrap()))
279            }
280            "*" => Ok((rest, arguments.into_iter().product())),
281            "/" if arguments.len() == 2 => {
282                let mut args = arguments.into_iter();
283                Ok((rest, args.next().unwrap() / args.next().unwrap()))
284            }
285            _ => Err(error()),
286        }
287    }
288
289    fn parse_literal<'a>(
290        &mut self,
291        l: &mut impl Iterator<Item = &'a str>,
292    ) -> Result<Option<(Assignment, Option<ENodeIdx>)>> {
293        let Some(lit) = l.next() else {
294            return Ok(None);
295        };
296        let (lit, value) = match lit {
297            // Have never seen this, but it is possible according to z3 source.
298            "true" | "false" => return Err(E::BoolLiteral),
299            "(not" => {
300                let lit = l.next().ok_or(E::UnexpectedNewline)?;
301                let lit = lit.strip_suffix(')').ok_or(E::TupleMissingParens)?;
302                (lit, false)
303            }
304            _ => (lit, true),
305        };
306        let literal = self.parse_existing_app(lit)?;
307        let enode = self.get_existing_enode(literal).ok();
308        Ok(Some((Assignment { literal, value }, enode)))
309    }
310
311    /// When logging `assign` z3 prints some literals as their "bool var idx"
312    /// rather than translating them through its `m_bool_var2expr` to print a
313    /// "#id".
314    ///
315    /// These look like `p123` and `(not p123)` in <= v4.8.9, or `123`
316    /// and `-123` in >= v4.8.10. Unfortunately we don't have the
317    /// `m_bool_var2expr` map so can't translate these back to a `TermIdx`. The
318    /// literal is rarely also `true` or `false` (for which this returns `None`)
319    fn parse_bool_literal<'a>(
320        version_info: &VersionInfo,
321        l: &mut impl Iterator<Item = &'a str>,
322    ) -> Result<Option<(Option<NonZeroU32>, bool)>> {
323        let Some(lit) = l.next() else {
324            return Ok(None);
325        };
326        match lit {
327            "" => {
328                debug_assert_eq!(l.next().filter(|n| !n.is_empty()), None);
329                return Ok(None);
330            }
331            "true" => return Ok(Some((None, true))),
332            "false" => return Ok(Some((None, false))),
333            _ => (),
334        };
335
336        let new_mode = version_info.is_ge_version(4, 8, 10);
337        let (lit, value) = if new_mode {
338            let noneg = lit.strip_prefix('-');
339            (noneg.unwrap_or(lit), noneg.is_none())
340        } else {
341            let (lit, value) = if lit == "(not" {
342                let lit = l.next().ok_or(E::UnexpectedNewline)?;
343                let lit = lit.strip_suffix(')').ok_or(E::TupleMissingParens)?;
344                (lit, false)
345            } else {
346                (lit, true)
347            };
348            (lit.strip_prefix('p').ok_or(E::BoolLiteralNotP)?, value)
349        };
350        let bool_lit = lit.parse::<NonZeroU32>().map_err(E::InvalidBoolLiteral)?;
351        Ok(Some((Some(bool_lit), value)))
352    }
353}
354
355impl Z3LogParser for Z3Parser {
356    fn newline(&mut self) {
357        self.comm.newline();
358    }
359
360    fn version_info<'a>(&mut self, mut l: impl Iterator<Item = &'a str>) -> Result<()> {
361        let solver = l.next().ok_or(E::UnexpectedNewline)?.to_string();
362        let version = l.next().ok_or(E::UnexpectedNewline)?;
363        // Return if there is unexpectedly more data
364        Self::expect_completed(l)?;
365        let version = semver::Version::parse(version)?;
366        eprintln!("{solver} {version}");
367        self.version_info = VersionInfo::Present { solver, version };
368        Ok(())
369    }
370
371    fn mk_quant<'a>(&mut self, mut l: impl Iterator<Item = &'a str>) -> Result<()> {
372        let full_id = self.parse_new_full_id(l.next())?;
373        let (quant_name, num_vars) = self.parse_qid(&mut l)?;
374        let quant_name = QuantKind::parse(&mut self.strings, &quant_name);
375        let child_ids = Self::map(l, |id| self.parse_existing_app(id))?;
376        debug_assert!(!child_ids.is_empty());
377        let child_id_names = || {
378            child_ids[..child_ids.len() - 1]
379                .iter()
380                .map(|&id| self[id].app_name().map(|name| &self[name]))
381        };
382        debug_assert!(
383            child_id_names().all(|name| name.is_some_and(|name| name == "pattern")),
384            "Expected all but last child to be \"pattern\" but found {:?}",
385            child_id_names().collect::<Vec<_>>()
386        );
387        self.quant_or_lamda(full_id, child_ids, num_vars, quant_name)
388    }
389
390    fn mk_lambda<'a>(&mut self, mut l: impl Iterator<Item = &'a str>) -> Result<()> {
391        let full_id = self.parse_new_full_id(l.next())?;
392        let lambda = l.next().ok_or(E::UnexpectedNewline)?;
393        self.check_lambda_name(lambda)?;
394        let num_vars = l.next().ok_or(E::UnexpectedNewline)?;
395        let num_vars = num_vars
396            .parse::<NonMaxU32>()
397            .map_err(E::InvalidQVarInteger)?;
398        let child_ids = Self::map(l, |id| self.parse_existing_proof(id))?;
399        let kind = QuantKind::Lambda(child_ids);
400        self.quant_or_lamda(full_id, Default::default(), num_vars, kind)
401    }
402
403    fn mk_var<'a>(&mut self, mut l: impl Iterator<Item = &'a str>) -> Result<()> {
404        let full_id = self.parse_new_full_id(l.next())?;
405        let kind = l.next().ok_or(E::UnexpectedNewline)?;
406        let kind = TermKind::parse_var(kind)?;
407        // Return if there is unexpectedly more data
408        Self::expect_completed(l)?;
409        self.new_term(full_id, kind, Default::default())?;
410        Ok(())
411    }
412
413    fn mk_app<'a>(&mut self, mut l: impl Iterator<Item = &'a str>) -> Result<()> {
414        let id_str = l.next().ok_or(E::UnexpectedNewline)?;
415        let mut id = TermId::parse(&mut self.strings, id_str)?;
416        let (name, child) = self.parse_app_name(&mut l)?;
417        debug_assert!(id_str != "#1" || name == "true");
418        debug_assert!(id_str != "#2" || name == "false");
419        self.terms
420            .check_get_model(&mut id, &name, &mut self.strings);
421        let name = self.mk_string(&name)?;
422        let child = child.into_iter().map(Ok);
423        let child_ids = child.chain(l.map(|id| TermId::parse(&mut self.strings, id)));
424        let child_ids = Self::map(child_ids, |id| self.terms.parse_app_child_id(id?))?;
425        let tidx = self.new_term(id, TermKind::App(name), child_ids)?;
426        self.events
427            .new_term(tidx, &self.terms[tidx], &self.strings)?;
428        Ok(())
429    }
430
431    fn mk_proof<'a>(&mut self, mut l: impl Iterator<Item = &'a str>) -> Result<()> {
432        let full_id = self.parse_new_full_id(l.next())?;
433        let name = l.next().ok_or(E::UnexpectedNewline)?;
434        let kind = match name.parse() {
435            Ok(kind) => kind,
436            Err(_) => {
437                debug_assert!(false, "Unknown proof step kind {name:?}");
438                ProofStepKind::OTHER(self.mk_string(name)?)
439            }
440        };
441        let mut next = l.next().ok_or(E::UnexpectedNewline)?;
442        let mut prerequisites = Vec::new();
443        for n in l {
444            let curr = next;
445            next = n;
446
447            let prereq = self.parse_existing_proof(curr)?;
448            prerequisites.push(prereq);
449        }
450        let result = self.parse_existing_app(next)?;
451
452        let proof_step = ProofStep {
453            id: full_id,
454            kind,
455            result,
456            prerequisites: prerequisites.into(),
457            frame: self.stack.active_frame(),
458        };
459        let proof_idx = self.terms.proof_terms.new_term(proof_step)?;
460        self.egraph
461            .new_proof(result, proof_idx, &self.terms, &self.stack)?;
462        self.events.new_proof_step(
463            proof_idx,
464            &self.terms[proof_idx],
465            &self.terms,
466            &self.strings,
467        )
468    }
469
470    fn attach_meaning<'a>(&mut self, mut l: impl Iterator<Item = &'a str>) -> Result<()> {
471        let id = l.next().ok_or(E::UnexpectedNewline)?;
472        let theory = l.next().ok_or(E::UnexpectedNewline)?;
473        let value = l.collect::<Vec<_>>().join(" ");
474        let meaning = match theory {
475            "arith" => {
476                let num = Self::parse_arith(&value)?;
477                Meaning::Arith(Box::new(num))
478            }
479            "bv" => {
480                let (value, bits) = if let Some(data) = value.strip_prefix("#x") {
481                    let value = num::BigUint::from_str_radix(data, 16);
482                    (value, data.len() as u32 * 4)
483                } else if let Some(data) = value.strip_prefix("#b") {
484                    let value = num::BigUint::from_str_radix(data, 2);
485                    (value, data.len() as u32)
486                } else {
487                    return Err(E::ParseError(value));
488                };
489                let value = BitVec {
490                    value: value.map_err(E::ParseBigUintError)?.into(),
491                    bits,
492                };
493                Meaning::BitVec(Box::new(value))
494            }
495            theory => {
496                let theory = self.mk_string(theory)?;
497                let value = self.mk_string(&value)?;
498                Meaning::Unknown { theory, value }
499            }
500        };
501        let idx = self.parse_existing_app(id)?;
502        let idx = self.terms.new_meaning(idx, meaning)?;
503        let meaning = self.terms.meaning(idx).unwrap();
504        self.events.new_meaning(idx, meaning, &self.strings)
505    }
506
507    fn attach_var_names<'a>(&mut self, mut l: impl Iterator<Item = &'a str>) -> Result<()> {
508        let id = l.next().ok_or(E::UnexpectedNewline)?;
509        let var_names = self.gobble_var_names_list(l)?;
510        let tidx = self.parse_existing_app(id)?;
511        let qidx = self.terms.quant(tidx)?;
512        let quant = &mut self.quantifiers[qidx];
513        debug_assert_eq!(quant.num_vars.get() as usize, var_names.len());
514        debug_assert!(quant.vars.is_none());
515        quant.vars = Some(var_names);
516        Ok(())
517    }
518
519    fn attach_enode<'a>(&mut self, mut l: impl Iterator<Item = &'a str>) -> Result<()> {
520        let id = l.next().ok_or(E::UnexpectedNewline)?;
521        let idx = self.parse_existing_app(id);
522        let Ok(idx) = idx else {
523            if self.version_info.is_version(4, 8, 7) {
524                // Z3 4.8.7 seems to have a bug where it can emit a non-existent term id here.
525                return Ok(());
526            } else {
527                return idx.map(|_| ());
528            }
529        };
530        let z3_gen = Self::parse_z3_generation(&mut l)?.ok_or(E::UnexpectedNewline)?;
531        // Return if there is unexpectedly more data
532        Self::expect_completed(l)?;
533
534        debug_assert!(self[idx].app_name().is_some());
535        let iidx = self.active_inst(idx)?;
536        let blame = self.egraph.get_blame(idx, iidx, &self.terms, &self.stack);
537        let enode = self.egraph.new_enode(blame, idx, z3_gen, &self.stack)?;
538        self.events.new_enode();
539        if let Some(a) = self.insts.active_inst() {
540            // If `None` then this is a ground term not created by an instantiation.
541            a.yields.try_reserve(1)?;
542            a.yields.push(enode);
543            let idx = a.idx;
544            debug_assert!(self.insts.insts[idx]
545                .kind
546                .z3_generation()
547                .is_none_or(|g| g == z3_gen));
548        }
549        Ok(())
550    }
551
552    fn eq_expl<'a>(&mut self, mut l: impl Iterator<Item = &'a str>) -> Result<()> {
553        let from = self.parse_existing_enode(l.next().ok_or(E::UnexpectedNewline)?)?;
554        let kind = l.next().ok_or(E::UnexpectedNewline)?;
555        let eq_expl = {
556            let mut kind_dependent_info = Self::iter_until_eq(l.by_ref(), ";");
557            match kind {
558                "root" => EqualityExpl::Root { id: from },
559                "lit" => {
560                    let eq = kind_dependent_info.next().ok_or(E::UnexpectedEnd)?;
561                    let eq = self.parse_existing_enode(eq)?;
562                    Self::expect_completed(kind_dependent_info)?;
563                    let to = self.parse_existing_enode(l.next().ok_or(E::UnexpectedNewline)?)?;
564
565                    let eq = self.lits.get_assign(self[eq].owner, &self.stack);
566                    let eq = eq.ok_or(E::UnknownEqLit)?;
567                    // The equality must have been assigned to true
568                    // TODO: why is this not always true?
569                    // debug_assert!(self[eq].term.value);
570                    EqualityExpl::Literal { from, eq, to }
571                }
572                "cg" => {
573                    let mut arg_eqs = Vec::new();
574                    for t in Self::gobble_tuples::<true>(kind_dependent_info) {
575                        let (from, to) = t?;
576                        let from = self.parse_existing_enode(from)?;
577                        let to = self.parse_existing_enode(to)?;
578                        arg_eqs.push((from, to));
579                    }
580                    let to = self.parse_existing_enode(l.next().ok_or(E::UnexpectedNewline)?)?;
581                    EqualityExpl::Congruence {
582                        from,
583                        arg_eqs: arg_eqs.into_boxed_slice(),
584                        to,
585                        uses: Vec::new(),
586                    }
587                }
588                "th" => {
589                    let theory = kind_dependent_info.next().ok_or(E::UnexpectedEnd)?;
590                    let theory = TheoryKind::from_name(theory, &mut self.strings);
591                    Self::expect_completed(kind_dependent_info)?;
592                    let to = self.parse_existing_enode(l.next().ok_or(E::UnexpectedNewline)?)?;
593                    EqualityExpl::Theory { from, theory, to }
594                }
595                "ax" => {
596                    Self::expect_completed(kind_dependent_info)?;
597                    let to = self.parse_existing_enode(l.next().ok_or(E::UnexpectedNewline)?)?;
598                    EqualityExpl::Axiom { from, to }
599                }
600                kind => {
601                    let args = kind_dependent_info
602                        .map(|s| self.mk_string(s))
603                        .collect::<Result<_>>()?;
604                    let to = self.parse_existing_enode(l.next().ok_or(E::UnexpectedNewline)?)?;
605                    EqualityExpl::Unknown {
606                        kind: self.mk_string(kind)?,
607                        from,
608                        args,
609                        to,
610                    }
611                }
612            }
613        };
614        // Return if there is unexpectedly more data
615        Self::expect_completed(l)?;
616
617        self.egraph.new_given_equality(from, eq_expl, &self.stack)?;
618        Ok(())
619    }
620
621    fn new_match<'a>(&mut self, mut l: impl Iterator<Item = &'a str>) -> Result<()> {
622        let fingerprint = l.next().ok_or(E::UnexpectedNewline)?;
623        let fingerprint = Fingerprint::parse(fingerprint)?;
624        let idx = l.next().ok_or(E::UnexpectedNewline)?;
625        let idx = self.parse_existing_app(idx)?;
626        let quant = self.terms.quant(idx)?;
627        let pattern = l.next().ok_or(E::UnexpectedNewline)?;
628        let pattern = self.parse_existing_app(pattern)?;
629        let pattern = self
630            .patterns(quant)
631            .ok_or(E::NewMatchOnLambda(quant))?
632            .position(|p| *p == pattern)
633            .ok_or(E::UnknownPatternIdx(pattern))?;
634        let bound_terms = Self::iter_until_eq(&mut l, ";");
635        let is_axiom = fingerprint.is_zero();
636
637        let kind = if is_axiom {
638            let bound_terms = bound_terms
639                .map(|id| self.parse_existing_app(id))
640                .collect::<Result<BoxSlice<_>>>()?;
641            debug_assert!(bound_terms
642                .iter()
643                .all(|&b| !self[b].has_var().unwrap_or(true)));
644            MatchKind::Axiom {
645                axiom: quant,
646                pattern,
647                bound_terms,
648            }
649        } else {
650            let bound_terms = bound_terms
651                .map(|id| self.parse_existing_enode(id))
652                .collect::<Result<BoxSlice<_>>>()?;
653            debug_assert!(bound_terms
654                .iter()
655                .all(|&b| !self[self[b].owner].has_var().unwrap_or(true)));
656            MatchKind::Quantifier {
657                quant,
658                pattern,
659                bound_terms,
660            }
661        };
662        let mut blamed = Vec::new();
663        let mut next = l.next();
664        while let Some(word) = next.take() {
665            let enode = self.parse_existing_enode(word)?;
666            // `append_trans_equality_tuples` would gobble the next term otherwise, so capture it instead.
667            let l = l.by_ref().take_while(|s| {
668                let cond = s.as_bytes().first().is_some_and(|f| *f == b'(')
669                    || s.as_bytes().last().is_some_and(|l| *l == b')');
670                if !cond {
671                    next = Some(*s);
672                }
673                cond
674            });
675            let mut equalities = Vec::new();
676            self.append_trans_equality_tuples(l, |eq| {
677                equalities.try_reserve(1)?;
678                equalities.push(eq);
679                Ok(())
680            })?;
681
682            blamed.try_reserve(1)?;
683            blamed.push((blamed.len(), enode, equalities));
684        }
685
686        let pat = kind.quant_pat().unwrap();
687        let pat = self.get_pattern(pat).unwrap();
688        let (_correct_order, blamed) = self.make_blamed(&kind, blamed, pat)?;
689
690        let match_ = Match {
691            kind,
692            blamed,
693            frame: self.stack.active_frame(),
694        };
695        debug_assert_eq!(match_.pattern_matches().count(), self[pat].child_ids.len());
696        debug_assert!(match_
697            .pattern_matches()
698            .zip(self[pat].child_ids.iter())
699            .all(|(m, s)| self.check_match(&match_.kind, m, *s)));
700        self.insts.new_match(fingerprint, match_)?;
701        Ok(())
702    }
703
704    fn inst_discovered<'a>(&mut self, mut l: impl Iterator<Item = &'a str>) -> Result<()> {
705        let method = l.next().ok_or(E::UnexpectedNewline)?;
706        let fingerprint = Fingerprint::parse(l.next().ok_or(E::UnexpectedNewline)?)?;
707
708        let (kind, blamed) = match method {
709            "theory-solving" => {
710                debug_assert!(
711                    fingerprint.is_zero(),
712                    "Theory solving should have zero fingerprint"
713                );
714                let axiom_id = l.next().ok_or(E::UnexpectedNewline)?;
715                let axiom_id = TermId::parse(&mut self.strings, axiom_id)?;
716
717                let bound_terms = Self::iter_until_eq(&mut l, ";")
718                    .map(|id| self.parse_existing_app(id))
719                    .collect::<Result<_>>()?;
720
721                let mut blamed = Vec::new();
722                let mut rewrite_of = None;
723                for word in l.by_ref() {
724                    let term = self.parse_existing_app(word)?;
725                    if let Ok(enode) = self.get_existing_enode(term) {
726                        if let Some(rewrite_of) = rewrite_of {
727                            return Err(E::NonRewriteAxiomInvalidEnode(rewrite_of));
728                        }
729                        blamed.try_reserve(1)?;
730                        // TODO: are the enodes in the correct order here?
731                        blamed.push(Blame {
732                            coupling: Coupling::Exact,
733                            enode,
734                            equalities: Default::default(),
735                        });
736                    } else {
737                        if let Some(rewrite_of) = rewrite_of {
738                            return Err(E::RewriteAxiomMultipleTerms1(rewrite_of));
739                        }
740                        if !blamed.is_empty() {
741                            return Err(E::RewriteAxiomMultipleTerms2(blamed));
742                        }
743                        rewrite_of = Some(term);
744                    }
745                }
746
747                let kind = MatchKind::TheorySolving {
748                    axiom_id,
749                    bound_terms,
750                    rewrite_of,
751                };
752                (kind, blamed)
753            }
754            "MBQI" => {
755                let quant = self.parse_existing_app(l.next().ok_or(E::UnexpectedNewline)?)?;
756                let quant = self.terms.quant(quant)?;
757                let bound_terms = l
758                    .map(|id| self.parse_existing_enode(id))
759                    .collect::<Result<_>>()?;
760                let kind = MatchKind::MBQI { quant, bound_terms };
761                (kind, Vec::new())
762            }
763            _ => return Err(E::UnknownInstMethod(method.to_string())),
764        };
765        let match_ = Match {
766            kind,
767            blamed: blamed.into(),
768            frame: self.stack.active_frame(),
769        };
770        self.insts.new_match(fingerprint, match_)?;
771        Ok(())
772    }
773
774    fn instance<'a>(&mut self, mut l: impl Iterator<Item = &'a str>) -> Result<()> {
775        let fingerprint = l.next().ok_or(E::UnexpectedNewline)?;
776        let fingerprint = Fingerprint::parse(fingerprint)?;
777        let mut proof = Self::iter_until_eq(&mut l, ";");
778        let proof_str = proof.next();
779        Self::expect_completed(proof)?;
780        let z3_generation = Self::parse_z3_generation(&mut l)?;
781        let kind = if let Some(z3_generation) = z3_generation {
782            debug_assert!(!fingerprint.is_zero());
783            let proof = if let Some(proof) = proof_str {
784                let proof = self.parse_existing_proof(proof)?;
785                InstProofLink::HasProof(proof)
786            } else {
787                let last_term = self.terms.last_term_from_instance(&self.strings);
788                InstProofLink::ProofsDisabled(last_term)
789            };
790            InstantiationKind::NonAxiom {
791                fingerprint,
792                z3_generation,
793                proof,
794            }
795        } else {
796            debug_assert!(fingerprint.is_zero());
797            // It seems that for `0x0` fingerprints the proof term points to an
798            // app term (usually an equality), while for "real" fingerprints it
799            // points to a proof term.
800            let proof = proof_str.expect("Axiom instantiations should have an associated term");
801            let body = self.parse_existing_app(proof)?;
802            InstantiationKind::Axiom { body }
803        };
804        let match_ = self
805            .insts
806            .get_match(fingerprint)
807            .ok_or(E::UnknownFingerprint(fingerprint))?;
808        let inst = Instantiation {
809            match_,
810            kind,
811            yields_terms: Default::default(),
812            frame: self.stack.active_frame(),
813        };
814        let body = self.instance_body(kind.proof(), match_);
815        // I have very rarely seen duplicate `[instance]` lines with the same
816        // fingerprint in >= v4.12.2. Allow these there and debug panic otherwise.
817        let can_duplicate = self.version_info.is_ge_version(4, 12, 0);
818        self.insts
819            .new_inst(fingerprint, inst, body, &self.stack, can_duplicate)?;
820        self.events.new_inst();
821        Ok(())
822    }
823
824    fn end_of_instance<'a>(&mut self, l: impl Iterator<Item = &'a str>) -> Result<()> {
825        self.insts.end_inst()?;
826        Self::expect_completed(l)
827    }
828
829    fn eof(&mut self) {
830        self.synth_terms.eof(self.terms().next_key());
831        self.events.new_eof();
832    }
833
834    fn assign<'a>(&mut self, mut l: impl Iterator<Item = &'a str>) -> Result<()> {
835        let created_by = self.insts.active_inst();
836        let iidx = created_by.as_ref().map(|a| a.idx);
837
838        let (assign, enode) = self.parse_literal(&mut l)?.ok_or(E::UnexpectedNewline)?;
839        let lit = self.lits.new_literal(assign, iidx, enode, &self.stack)?;
840        let mut justification = l.next().ok_or(E::UnexpectedNewline)?;
841        let decision = justification == "decision";
842        if decision {
843            let llk = self.comm.prev().last_line_kind;
844            // TODO: the bitvector-only solver in z3 doesn't use push/pop
845            // debug_assert_eq!(llk, LineKind::Push);
846            if matches!(llk, LineKind::Push) && self.stack.new_decision() {
847                self.push_count -= 1;
848                self.events.undo_push();
849            }
850            self.lits.cdcl.new_decision(lit, &self.stack)?;
851            justification = l.next().ok_or(E::UnexpectedNewline)?;
852            debug_assert_eq!(justification, "axiom");
853        }
854        // Now `l` contains
855        match justification {
856            // Either a "decision" or a non-interesting assignment by e.g.
857            // internal z3 axioms.
858            "axiom" => {
859                Self::expect_completed(l)?;
860                let kind = if decision {
861                    JustificationKind::Decision
862                } else {
863                    JustificationKind::Axiom
864                };
865                self.lits.justification(lit, kind, core::iter::empty())?;
866                Ok(())
867            }
868            // Same as clause, but binary?
869            "bin" => {
870                let other = Self::parse_bool_literal(&self.version_info, &mut l)?
871                    .ok_or(E::UnexpectedNewline)?;
872                Self::expect_completed(l)?;
873
874                let _j = self.lits.justification(
875                    lit,
876                    JustificationKind::Propagate,
877                    [Ok(other)].into_iter(),
878                )?;
879                // Issue 3: No way to convert LitId -> TermIdx
880                #[cfg(any())]
881                debug_assert_ne!(lit, j.blamed[0]);
882                self.lits.cdcl.new_propagate(lit, &self.stack)?;
883                Ok(())
884            }
885            // A propagated assignment: a clause only has one unassigned literal
886            // left. The offending clause is also printed but since it's in
887            // bool-var format we can't use it. Also <= v4.8.8 prints the text
888            // name of each clause on subsequent newlines, we'll ignore those.
889            // Later versions of z3 use `display_compact_j`.
890            "clause" => {
891                let _first = Self::parse_bool_literal(&self.version_info, &mut l)?
892                    .ok_or(E::UnexpectedNewline)?;
893                // All the other literals in the clause (which have already been assigned)
894                let lits = core::iter::from_fn(|| {
895                    Self::parse_bool_literal(&self.version_info, &mut l).transpose()
896                });
897                self.lits
898                    .justification(lit, JustificationKind::Propagate, lits)?;
899
900                // Issue 3: No way to convert LitId -> TermIdx
901                #[cfg(any())]
902                let c0 = self.lits.literal_to_term(first, false)?;
903                #[cfg(any())]
904                if lit != c0 {
905                    eprintln!(
906                        "Unexpected clause literal: {lit} != {c0} ({first:?}) / {:?}",
907                        self.lits.lit_stack
908                    );
909                    return Err(E::UnexpectedEnd);
910                }
911                #[cfg(any())]
912                debug_assert_eq!(lit, c0, "{first:?}");
913                self.lits.cdcl.new_propagate(lit, &self.stack)?;
914                Ok(())
915            }
916            "justification" => {
917                let theory_id = l.next().ok_or(E::UnexpectedNewline)?;
918                let theory_id = theory_id
919                    .strip_suffix(':')
920                    .ok_or(E::MissingColonJustification)?;
921                let theory_id = theory_id.parse::<i32>().map_err(E::InvalidTheoryId)?;
922                let theory = TheoryKind::from_id(theory_id);
923
924                let lits = core::iter::from_fn(|| {
925                    Self::parse_bool_literal(&self.version_info, &mut l).transpose()
926                });
927                self.lits
928                    .justification(lit, JustificationKind::Theory(theory), lits)?;
929                Ok(())
930            }
931            _ => Err(E::UnknownJustification(justification.to_string())),
932        }
933    }
934
935    fn decide_and_or<'a>(&mut self, _l: impl Iterator<Item = &'a str>) -> Result<()> {
936        self.comm.curr().last_line_kind = LineKind::DecideAndOr;
937        Ok(())
938    }
939
940    fn conflict<'a>(&mut self, mut l: impl Iterator<Item = &'a str>) -> Result<()> {
941        self.comm.curr().last_line_kind = LineKind::Conflict;
942
943        let mut cut = Vec::new();
944        while let Some((assignment, _)) = self.parse_literal(&mut l)? {
945            cut.try_reserve(1)?;
946            cut.push(assignment);
947        }
948        let frame = self.stack.active_frame();
949        debug_assert!(self.lits.curr_to_root_unique());
950        self.lits.cdcl.new_conflict(cut.into_boxed_slice(), frame);
951        // Backtracking will happen with the pop in the next line. We'll push
952        // the new (opposite) decision there.
953        Ok(())
954    }
955
956    fn push<'a>(&mut self, mut l: impl Iterator<Item = &'a str>) -> Result<()> {
957        self.comm.curr().last_line_kind = LineKind::Push;
958
959        let scope = l.next().ok_or(E::UnexpectedNewline)?;
960        let scope = scope.parse::<usize>().map_err(E::InvalidFrameInteger)?;
961        // Return if there is unexpectedly more data
962        Self::expect_completed(l)?;
963
964        let from_cdcl = matches!(self.comm.prev().last_line_kind, LineKind::DecideAndOr);
965        let from_cdcl = from_cdcl || self.stack.is_speculative();
966        self.stack.new_frame(scope, from_cdcl)?;
967        if !from_cdcl {
968            self.push_count += 1;
969        }
970        self.events.new_push(from_cdcl)?;
971        Ok(())
972    }
973
974    fn pop<'a>(&mut self, mut l: impl Iterator<Item = &'a str>) -> Result<()> {
975        let num = l.next().ok_or(E::UnexpectedNewline)?;
976        let num = num
977            .parse::<NonZeroUsize>()
978            .map_err(E::InvalidFrameInteger)?;
979        let scope = l.next().ok_or(E::UnexpectedNewline)?;
980        let scope = scope.parse::<usize>().map_err(E::InvalidFrameInteger)?;
981        // Return if there is unexpectedly more data
982        Self::expect_completed(l)?;
983
984        let conflict = matches!(self.comm.prev().last_line_kind, LineKind::Conflict);
985        debug_assert_eq!(conflict, self.lits.cdcl.has_conflict());
986        let from_cdcl = self.stack.pop_frames(num, scope, conflict)?;
987        // I think `from_cdcl && !conflict` => end of a check-sat
988        if conflict {
989            self.lits.cdcl.backtrack(&self.stack)?;
990        }
991        self.events.new_pop(num, from_cdcl)
992    }
993
994    fn begin_check<'a>(&mut self, mut l: impl Iterator<Item = &'a str>) -> Result<()> {
995        let scope = l.next().ok_or(E::UnexpectedNewline)?;
996        let scope = scope.parse::<usize>().map_err(E::InvalidFrameInteger)?;
997        self.stack.ensure_height(scope)?;
998        self.lits
999            .cdcl
1000            .begin_check(self.incremental_mode(), &self.stack)?;
1001        self.events.new_begin_check()
1002    }
1003}