polar_core/
query.rs

1use super::error::PolarResult;
2use super::events::*;
3use super::messages::*;
4use super::runnable::Runnable;
5use super::terms::*;
6use super::vm::*;
7
8pub struct Query {
9    runnable_stack: Vec<(Box<dyn Runnable>, u64)>, // Tuple of Runnable + call_id.
10    vm: PolarVirtualMachine,
11    term: Term,
12    done: bool,
13}
14
15impl Query {
16    pub fn new(vm: PolarVirtualMachine, term: Term) -> Self {
17        Self {
18            runnable_stack: vec![],
19            vm,
20            term,
21            done: false,
22        }
23    }
24
25    #[cfg(target_arch = "wasm32")]
26    pub fn set_logging_options(&mut self, rust_log: Option<String>, polar_log: Option<String>) {
27        self.vm.set_logging_options(rust_log, polar_log);
28    }
29
30    /// Runnable lifecycle
31    ///
32    /// 1. Get Runnable A from the top of the Runnable stack, defaulting to the VM.
33    /// 2. If Runnable A emits a Run event containing Runnable B, push Runnable B onto the stack.
34    /// 3. Immediately request the next event, which will execute Runnable B.
35    /// 4. When Runnable B emits a Done event, pop Runnable B off the stack and return its result as
36    ///    an answer to Runnable A.
37    pub fn next_event(&mut self) -> PolarResult<QueryEvent> {
38        let mut counter = self.vm.id_counter();
39        let qe = match self.top_runnable().run(Some(&mut counter)) {
40            Ok(e) => e,
41            Err(e) => self.top_runnable().handle_error(e)?,
42        };
43        self.recv_event(qe)
44    }
45
46    fn recv_event(&mut self, qe: QueryEvent) -> PolarResult<QueryEvent> {
47        match qe {
48            QueryEvent::None => self.next_event(),
49            QueryEvent::Run { runnable, call_id } => {
50                self.push_runnable(runnable, call_id);
51                self.next_event()
52            }
53            QueryEvent::Done { result } => {
54                if let Some((_, result_call_id)) = self.pop_runnable() {
55                    self.top_runnable()
56                        .external_question_result(result_call_id, result)?;
57                    self.next_event()
58                } else {
59                    // VM is done.
60                    assert!(self.runnable_stack.is_empty());
61                    Ok(QueryEvent::Done { result })
62                }
63            }
64            ev => Ok(ev),
65        }
66    }
67
68    fn top_runnable(&mut self) -> &mut (dyn Runnable) {
69        self.runnable_stack
70            .last_mut()
71            .map(|b| b.0.as_mut())
72            .unwrap_or(&mut self.vm)
73    }
74
75    fn push_runnable(&mut self, runnable: Box<dyn Runnable>, call_id: u64) {
76        self.runnable_stack.push((runnable, call_id));
77    }
78
79    fn pop_runnable(&mut self) -> Option<(Box<dyn Runnable>, u64)> {
80        self.runnable_stack.pop()
81    }
82
83    pub fn call_result(&mut self, call_id: u64, value: Option<Term>) -> PolarResult<()> {
84        self.top_runnable().external_call_result(call_id, value)
85    }
86
87    pub fn question_result(&mut self, call_id: u64, result: bool) -> PolarResult<()> {
88        self.top_runnable()
89            .external_question_result(call_id, result)
90    }
91
92    pub fn application_error(&mut self, message: String) -> PolarResult<()> {
93        self.vm.external_error(message)
94    }
95
96    pub fn debug_command(&mut self, command: &str) -> PolarResult<()> {
97        self.top_runnable().debug_command(command)
98    }
99
100    pub fn next_message(&self) -> Option<Message> {
101        self.vm.messages.next()
102    }
103
104    pub fn source_info(&self) -> String {
105        self.vm.term_source(&self.term, true)
106    }
107
108    pub fn bind(&mut self, name: Symbol, value: Term) -> PolarResult<()> {
109        self.vm.bind(&name, value)
110    }
111}
112
113// Query as an iterator returns `None` after the first time `Done` is seen
114impl Iterator for Query {
115    type Item = PolarResult<QueryEvent>;
116
117    fn next(&mut self) -> Option<PolarResult<QueryEvent>> {
118        if self.done {
119            return None;
120        }
121        let event = self.next_event();
122        if let Ok(QueryEvent::Done { .. }) = event {
123            self.done = true;
124        }
125        Some(event)
126    }
127}