trivial_kernel/stream/
unify.rs

1use crate::context::{store, Context, Ptr, Store};
2use crate::error::Kind;
3use crate::KResult;
4use crate::Table;
5use crate::Var;
6use core::convert::TryInto;
7use core::ops::Range;
8
9#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
10pub enum Mode {
11    Def,
12    Thm,
13    ThmEnd,
14}
15
16use crate::opcode;
17
18pub trait Unify {
19    fn end(&mut self, mode: Mode) -> KResult;
20
21    fn term(&mut self, idx: u32, save: bool) -> KResult;
22
23    fn reference(&mut self, idx: u32) -> KResult;
24
25    fn dummy(&mut self, sort: u32) -> KResult;
26
27    fn hyp_thm(&mut self) -> KResult;
28
29    fn hyp_thm_end(&mut self) -> KResult;
30
31    fn execute(&mut self, command: opcode::Command<opcode::Unify>, mode: Mode) -> KResult<bool> {
32        use crate::opcode::Unify::*;
33        match command.opcode {
34            End => {
35                self.end(mode)?;
36                return Ok(true);
37            }
38            Ref => self.reference(command.operand),
39            Term => self.term(command.operand, false),
40            TermSave => self.term(command.operand, true),
41            Dummy => match mode {
42                Mode::Def => self.dummy(command.operand),
43                _ => Err(Kind::DummyCommandInTheorem),
44            },
45            Hyp => match mode {
46                Mode::Def => Err(Kind::HypInDefStatement),
47                Mode::Thm => self.hyp_thm(),
48                Mode::ThmEnd => self.hyp_thm_end(),
49            },
50        }?;
51
52        Ok(false)
53    }
54}
55
56impl<S: Store> Unify for Context<S> {
57    fn end(&mut self, mode: Mode) -> KResult {
58        if mode == Mode::ThmEnd && self.hyp_stack.len() != 0 {
59            return Err(Kind::UnfinishedHypStack);
60        }
61
62        if self.unify_stack.len() != 0 {
63            return Err(Kind::UnfinishedUnifyStack);
64        }
65
66        Ok(())
67    }
68
69    fn term(&mut self, idx: u32, save: bool) -> KResult {
70        let ptr = self.unify_stack.pop().ok_or(Kind::UnifyStackUnderflow)?;
71
72        let term: store::Term<_> = self.store.get(ptr.into())?;
73
74        if *term.id != idx {
75            return Err(Kind::UnifyTermFailure);
76        }
77
78        for i in term.args.iter().rev() {
79            self.unify_stack.push(*i);
80        }
81
82        if save {
83            self.unify_heap.push(ptr);
84        }
85
86        Ok(())
87    }
88
89    fn reference(&mut self, idx: u32) -> KResult {
90        let x = self.unify_heap.get(idx).ok_or(Kind::InvalidHeapIndex)?;
91        let y = self.unify_stack.pop().ok_or(Kind::UnifyStackUnderflow)?;
92
93        if x == y {
94            Ok(())
95        } else {
96            Err(Kind::UnifyRefFailure)
97        }
98    }
99
100    fn dummy(&mut self, sort: u32) -> KResult {
101        let e = self
102            .unify_stack
103            .pop()
104            .ok_or(Kind::UnifyStackUnderflow)?
105            .as_expr()
106            .ok_or(Kind::InvalidStackType)?;
107
108        let var: store::Variable<_> = self.store.get(e)?;
109        let ty = var.ty;
110
111        if !(ty.is_bound() && ty.sort_idx() == (sort as u8)) {
112            return Err(Kind::UnifyTermFailure);
113        }
114
115        let deps = ty.dependencies();
116
117        for i in self.unify_heap.as_slice() {
118            let i = i.as_expr().ok_or(Kind::InvalidStoreExpr)?;
119            // todo: check if expr is the only type of pointer
120
121            let d = self
122                .store
123                .get_type_of_expr(i)
124                .ok_or(Kind::InvalidStoreExpr)?;
125
126            if d.depends_on_full(deps) {
127                return Err(Kind::DisjointVariableViolation);
128            }
129        }
130
131        self.unify_heap.push(e.to_expr());
132
133        Ok(())
134    }
135
136    fn hyp_thm(&mut self) -> KResult {
137        let proof = self
138            .proof_stack
139            .pop()
140            .ok_or(Kind::ProofStackUnderflow)?
141            .as_proof()
142            .ok_or(Kind::InvalidStackType)?;
143
144        self.unify_stack.push(proof.to_expr());
145
146        Ok(())
147    }
148
149    fn hyp_thm_end(&mut self) -> KResult {
150        if self.unify_stack.len() != 0 {
151            return Err(Kind::UnfinishedUnifyStack);
152        }
153
154        let e = self.hyp_stack.pop().ok_or(Kind::HypStackUnderflow)?;
155
156        self.unify_stack.push(e);
157
158        Ok(())
159    }
160}
161
162pub trait Run<S: Store> {
163    fn run<T>(&mut self, stream: Range<usize>, table: &T, mode: Mode, target: Ptr) -> KResult
164    where
165        T: Table<Var = S::Var>;
166}
167
168impl<S: Store> Run<S> for Context<S> {
169    fn run<T>(&mut self, stream: Range<usize>, table: &T, mode: Mode, target: Ptr) -> KResult
170    where
171        T: Table<Var = S::Var>,
172    {
173        self.unify_stack.clear();
174        self.unify_stack.push(target.to_expr());
175
176        let commands = table
177            .unify_commands(stream)
178            .ok_or(Kind::InvalidUnifyCommandIndex)?;
179
180        for i in commands {
181            let command = i.try_into().map_err(|_| Kind::UnknownCommand)?;
182
183            if self.execute(command, mode)? {
184                return Ok(());
185            }
186        }
187
188        Err(Kind::StreamExhausted)
189    }
190}
191
192#[derive(Debug, Clone, Eq, PartialEq, Hash)]
193pub struct Stepper {
194    started: bool,
195    done: bool,
196    mode: Mode,
197    target: Ptr,
198    stream: Range<usize>,
199}
200
201#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
202pub enum Action {
203    Started,
204    Cmd(usize, opcode::Command<opcode::Unify>),
205}
206
207impl Stepper {
208    pub fn new(mode: Mode, target: Ptr, stream: Range<usize>) -> Stepper {
209        Stepper {
210            started: false,
211            done: false,
212            mode,
213            target,
214            stream,
215        }
216    }
217
218    pub fn step<S: Store, T: Table<Var = S::Var>>(
219        &mut self,
220        context: &mut Context<S>,
221        table: &T,
222    ) -> KResult<Option<Action>> {
223        if self.done {
224            Ok(None)
225        } else if !self.started {
226            context.unify_stack.clear();
227            context.unify_stack.push(self.target.to_expr());
228            self.started = true;
229            Ok(Some(Action::Started))
230        } else {
231            let current_idx = self.stream.next();
232
233            match current_idx {
234                Some(idx) => {
235                    let command = table
236                        .unify_command(idx)
237                        .ok_or(Kind::InvalidUnifyCommandIndex)?;
238
239                    self.done = context.execute(*command, self.mode)?;
240
241                    Ok(Some(Action::Cmd(idx, *command)))
242                }
243                None => Ok(None),
244            }
245        }
246    }
247}