use std::{cmp, fmt::Debug};
use state::State;
use crate::{primitives::Builtins, utils::interner::Interner};
use super::{parser::ruleset::RuleSet, utils::PrimitiveFn};
pub mod state;
pub struct Engine {
pub state: State,
pub program: Program,
}
pub struct Program {
pub primitives: Vec<(Box<[usize]>, PrimitiveFn)>,
program: RuleSet,
}
#[derive(Debug)]
pub enum VeraEvent {
Continuing,
Error(VeraError),
}
#[derive(Debug)]
pub enum VeraError {
MaxStepsExceeded,
}
type StepCallback = Box<dyn Fn(&mut Engine, usize, VeraEvent)>;
impl Engine {
pub fn new(interner: Interner<String>) -> Self {
let regs = vec![];
let regs = regs.into_boxed_slice();
Engine {
state: State {
registers: regs,
interner,
},
program: Program {
primitives: vec![],
program: RuleSet::empty(),
},
}
}
pub fn with_builtins(&mut self, f: &dyn Fn(&mut Builtins, &mut Interner<String>)) {
let mut builtins = Builtins {
builtins: &mut self.program.primitives,
};
f(&mut builtins, &mut self.state.interner);
}
pub fn load_notecard(&mut self, code: &str) {
let notecard = crate::parser::parse(code, &mut self.state.interner);
self.program.program += notecard.unwrap();
}
pub fn run(&mut self, max_steps: usize, step_callback: StepCallback) -> usize {
let mut steps = 0;
self.setup();
while self.run_step() {
steps += 1;
if steps >= max_steps {
step_callback(self, steps, VeraEvent::Error(VeraError::MaxStepsExceeded));
break;
} else {
step_callback(self, steps, VeraEvent::Continuing);
}
}
steps
}
pub fn setup(&mut self) {
let registers = vec![0; self.state.interner.count()].into_boxed_slice();
self.state.registers = registers;
for fact in &self.program.program.facts {
for (register, multiplicity) in &fact.multiplicities {
self.state.produce(*register, *multiplicity);
}
}
}
pub fn run_step(&mut self) -> bool {
'prims: for (condition, primitive) in self.program.primitives.iter() {
for register in condition.iter() {
if !self.state.present(*register) {
continue 'prims;
}
}
primitive(&mut self.state, 0);
return true;
}
'rules: for rule in &self.program.program.rules {
let mut minimum = usize::MAX;
for register in rule.conditions.iter() {
let value = self.state.value(register.0);
if value == 0 {
continue 'rules;
}
minimum = cmp::min(value, minimum);
}
for register in rule.conditions.iter() {
self.state.consume(register.0, minimum);
}
for (register, multiplicity) in rule.multiplicities.iter() {
self.state.produce(*register, minimum * *multiplicity);
}
return true;
}
false
}
pub fn print_state(&mut self) {
self.state.print_state();
}
}