mirror of
https://github.com/microsoft/regorus.git
synced 2026-08-05 02:16:11 +00:00
add full api to engine (#50)
Signed-off-by: eric-therond <eric.therond.fr@gmail.com>
This commit is contained in:
116
src/engine.rs
116
src/engine.rs
@@ -6,6 +6,7 @@ use crate::interpreter::*;
|
||||
use crate::lexer::*;
|
||||
use crate::parser::*;
|
||||
use crate::scheduler::*;
|
||||
use crate::utils::gather_functions;
|
||||
use crate::value::*;
|
||||
|
||||
use anyhow::Result;
|
||||
@@ -13,8 +14,8 @@ use anyhow::Result;
|
||||
#[derive(Clone)]
|
||||
pub struct Engine {
|
||||
modules: Vec<Ref<Module>>,
|
||||
input: Value,
|
||||
data: Value,
|
||||
interpreter: Interpreter,
|
||||
prepared: bool,
|
||||
}
|
||||
|
||||
impl Default for Engine {
|
||||
@@ -27,8 +28,8 @@ impl Engine {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
modules: vec![],
|
||||
input: Value::new_object(),
|
||||
data: Value::new_object(),
|
||||
interpreter: Interpreter::new(),
|
||||
prepared: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +37,8 @@ impl Engine {
|
||||
let source = Source::new(path, rego);
|
||||
let mut parser = Parser::new(&source)?;
|
||||
self.modules.push(Ref::new(parser.parse()?));
|
||||
// if policies change, interpreter needs to be prepared again
|
||||
self.prepared = false;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -43,36 +46,105 @@ impl Engine {
|
||||
let source = Source::from_file(path)?;
|
||||
let mut parser = Parser::new(&source)?;
|
||||
self.modules.push(Ref::new(parser.parse()?));
|
||||
self.prepared = false;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_input(&mut self, input: Value) {
|
||||
self.input = input;
|
||||
self.interpreter.set_input(input);
|
||||
}
|
||||
|
||||
pub fn clear_data(&mut self) {
|
||||
self.data = Value::new_object();
|
||||
self.interpreter.set_data(Value::new_object());
|
||||
self.prepared = false;
|
||||
}
|
||||
|
||||
pub fn add_data(&mut self, data: Value) -> Result<()> {
|
||||
self.data.merge(data)
|
||||
self.prepared = false;
|
||||
self.interpreter.get_data_mut().merge(data)
|
||||
}
|
||||
|
||||
pub fn eval_query(&self, query: String, enable_tracing: bool) -> Result<QueryResults> {
|
||||
// Analyze the modules and determine how statements must be scheduled.
|
||||
let analyzer = Analyzer::new();
|
||||
let schedule = analyzer.analyze(&self.modules)?;
|
||||
pub fn get_modules(&mut self) -> &Vec<Ref<Module>> {
|
||||
&self.modules
|
||||
}
|
||||
|
||||
// Create interpreter object.
|
||||
let mut interpreter = Interpreter::new(&self.modules)?;
|
||||
fn prepare_for_eval(&mut self, enable_tracing: bool) -> Result<()> {
|
||||
self.interpreter.set_traces(enable_tracing);
|
||||
|
||||
// Evaluate all the modules.
|
||||
interpreter.eval(
|
||||
&Some(self.data.clone()),
|
||||
&Some(self.input.clone()),
|
||||
false,
|
||||
Some(schedule),
|
||||
)?;
|
||||
// if the data/policies have changed or the interpreter has never been prepared
|
||||
if !self.prepared {
|
||||
// Analyze the modules and determine how statements must be scheduled.
|
||||
let analyzer = Analyzer::new();
|
||||
let schedule = analyzer.analyze(&self.modules)?;
|
||||
|
||||
self.interpreter.init_with_document()?;
|
||||
self.interpreter.set_schedule(Some(schedule));
|
||||
self.interpreter.set_modules(&self.modules);
|
||||
|
||||
self.interpreter.clear_builtins_cache();
|
||||
// when the interpreter is prepared the initial data is saved
|
||||
// the data will be reset to init_data each time clean_internal_evaluation_state is called
|
||||
let init_data = self.interpreter.get_data_mut().clone();
|
||||
self.interpreter.set_init_data(init_data);
|
||||
|
||||
self.interpreter
|
||||
.set_functions(gather_functions(&self.modules)?);
|
||||
self.interpreter.gather_rules()?;
|
||||
self.prepared = true;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn eval_rule(
|
||||
&mut self,
|
||||
module: &Ref<Module>,
|
||||
rule: &Ref<Rule>,
|
||||
enable_tracing: bool,
|
||||
) -> Result<Value> {
|
||||
self.prepare_for_eval(enable_tracing)?;
|
||||
self.interpreter.clean_internal_evaluation_state();
|
||||
|
||||
self.interpreter.eval_rule(module, rule)?;
|
||||
|
||||
Ok(self.interpreter.get_data_mut().clone())
|
||||
}
|
||||
|
||||
pub fn eval_modules(&mut self, enable_tracing: bool) -> Result<Value> {
|
||||
self.prepare_for_eval(enable_tracing)?;
|
||||
self.interpreter.clean_internal_evaluation_state();
|
||||
|
||||
// Ensure that each module has an empty object
|
||||
for m in &self.modules {
|
||||
let path = Parser::get_path_ref_components(&m.package.refr)?;
|
||||
let path: Vec<&str> = path.iter().map(|s| *s.text()).collect();
|
||||
let vref =
|
||||
Interpreter::make_or_get_value_mut(self.interpreter.get_data_mut(), &path[..])?;
|
||||
if *vref == Value::Undefined {
|
||||
*vref = Value::new_object();
|
||||
}
|
||||
}
|
||||
|
||||
self.interpreter.check_default_rules()?;
|
||||
for module in self.modules.clone() {
|
||||
for rule in &module.policy {
|
||||
self.interpreter.eval_rule(&module, rule)?;
|
||||
}
|
||||
}
|
||||
// Defer the evaluation of the default rules to here
|
||||
for module in self.modules.clone() {
|
||||
let prev_module = self.interpreter.set_current_module(Some(module.clone()))?;
|
||||
for rule in &module.policy {
|
||||
self.interpreter.eval_default_rule(rule)?;
|
||||
}
|
||||
self.interpreter.set_current_module(prev_module)?;
|
||||
}
|
||||
|
||||
Ok(self.interpreter.get_data_mut().clone())
|
||||
}
|
||||
|
||||
pub fn eval_query(&mut self, query: String, enable_tracing: bool) -> Result<QueryResults> {
|
||||
self.eval_modules(false)?;
|
||||
|
||||
// Parse the query.
|
||||
let query_len = query.len();
|
||||
@@ -88,7 +160,9 @@ impl Engine {
|
||||
let query_node = Ref::new(parser.parse_query(query_span, "")?);
|
||||
let query_schedule = Analyzer::new().analyze_query_snippet(&self.modules, &query_node)?;
|
||||
|
||||
let results = interpreter.eval_user_query(&query_node, &query_schedule, enable_tracing)?;
|
||||
let results =
|
||||
self.interpreter
|
||||
.eval_user_query(&query_node, &query_schedule, enable_tracing)?;
|
||||
Ok(results)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user