use prolog_parser::ast::*; use prolog_parser::parser::*; use crate::machine::machine_errors::CompilationError; use crate::machine::*; use indexmap::IndexSet; use std::collections::VecDeque; use std::fmt; pub(crate) trait TermStream: Sized { type Evacuable; fn next(&mut self, op_dir: &CompositeOpDir) -> Result; fn eof(&mut self) -> Result; fn listing_src(&self) -> &ListingSource; fn evacuate<'a>(loader: Loader<'a, Self>) -> Result; } #[derive(Debug)] pub(super) struct BootstrappingTermStream<'a> { listing_src: ListingSource, parser: Parser<'a, Stream>, } impl<'a> BootstrappingTermStream<'a> { #[inline] pub(super) fn from_prolog_stream( stream: &'a mut PrologStream, atom_tbl: TabledData, flags: MachineFlags, listing_src: ListingSource, ) -> Self { let parser = Parser::new(stream, atom_tbl, flags); Self { parser, listing_src, } } } impl<'a> TermStream for BootstrappingTermStream<'a> { type Evacuable = CompilationTarget; #[inline] fn next(&mut self, op_dir: &CompositeOpDir) -> Result { self.parser.reset(); self.parser .read_term(op_dir) .map_err(CompilationError::from) } #[inline] fn eof(&mut self) -> Result { self.parser.devour_whitespace()?; // eliminate dangling comments before checking for EOF. Ok(self.parser.eof()?) } #[inline] fn listing_src(&self) -> &ListingSource { &self.listing_src } fn evacuate(mut loader: Loader) -> Result { if !loader.predicates.is_empty() { loader.compile_and_submit()?; } loader .load_state .retraction_info .reset(loader.load_state.wam.code_repo.code.len()); loader.load_state.remove_module_op_exports(); Ok(loader.load_state.compilation_target.take()) } } pub struct LiveTermStream { pub(super) term_queue: VecDeque, pub(super) listing_src: ListingSource, } impl LiveTermStream { #[inline] pub(super) fn new(listing_src: ListingSource) -> Self { Self { term_queue: VecDeque::new(), listing_src, } } } pub struct LoadStatePayload { pub(super) term_stream: LiveTermStream, pub(super) compilation_target: CompilationTarget, pub(super) retraction_info: RetractionInfo, pub(super) module_op_exports: Vec<(OpDecl, Option<(usize, Specifier)>)>, pub(super) non_counted_bt_preds: IndexSet, pub(super) predicates: PredicateQueue, pub(super) clause_clauses: Vec<(Term, Term)>, } impl fmt::Debug for LoadStatePayload { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { write!(fmt, "LoadStatePayload") } } impl LoadStatePayload { pub(super) fn new(wam: &Machine) -> Self { Self { term_stream: LiveTermStream::new(ListingSource::User), compilation_target: CompilationTarget::default(), retraction_info: RetractionInfo::new(wam.code_repo.code.len()), module_op_exports: vec![], non_counted_bt_preds: IndexSet::new(), predicates: predicate_queue![], clause_clauses: vec![], } } } impl TermStream for LiveTermStream { type Evacuable = LoadStatePayload; #[inline] fn next(&mut self, _: &CompositeOpDir) -> Result { Ok(self.term_queue.pop_front().unwrap()) } #[inline] fn eof(&mut self) -> Result { return Ok(self.term_queue.is_empty()); } #[inline] fn listing_src(&self) -> &ListingSource { &self.listing_src } #[inline] fn evacuate(loader: Loader) -> Result { Ok(loader.to_load_state_payload()) } }