use crate::compile::knowledge::rule::Rule;
use crate::compile::knowledge::rule_dsl::ast::RuleDef;
use crate::compile::knowledge::rule_dsl::lower::LowerError;
use crate::compile::knowledge::rule_dsl::parser::{ParseError, Parser};
use std::collections::HashSet;
use std::path::Path;
#[derive(Debug, Clone, PartialEq, thiserror::Error)]
pub enum LoadError {
#[error("I/O error while loading rules: {0}")]
Io(String),
#[error("failed to parse rule DSL: {0}")]
Parse(ParseError),
#[error("failed to lower rule DSL: {0}")]
Lower(LowerError),
#[error("duplicate rule name: {0}")]
DuplicateRuleName(String),
}
pub fn load_rules_from_file(path: impl AsRef<Path>) -> Result<Vec<Rule>, LoadError> {
let source =
std::fs::read_to_string(path.as_ref()).map_err(|e| LoadError::Io(format!("{}", e)))?;
load_rules_from_str(&source)
}
pub fn load_rules_from_str(source: &str) -> Result<Vec<Rule>, LoadError> {
let defs = load_rule_defs_from_str(source)?;
validate_unique_rule_names(&defs)?;
defs.into_iter()
.map(RuleDef::into_rule)
.collect::<Result<Vec<_>, _>>()
.map_err(LoadError::Lower)
}
pub fn load_rule_defs_from_file(path: impl AsRef<Path>) -> Result<Vec<RuleDef>, LoadError> {
let source =
std::fs::read_to_string(path.as_ref()).map_err(|e| LoadError::Io(format!("{}", e)))?;
load_rule_defs_from_str(&source)
}
pub fn load_rule_defs_from_str(source: &str) -> Result<Vec<RuleDef>, LoadError> {
let mut parser = Parser::new(source).map_err(LoadError::Parse)?;
parser.parse_rule_file().map_err(LoadError::Parse)
}
fn validate_unique_rule_names(defs: &[RuleDef]) -> Result<(), LoadError> {
let mut seen = HashSet::with_capacity(defs.len());
for def in defs {
if !seen.insert(def.name.as_str()) {
return Err(LoadError::DuplicateRuleName(def.name.clone()));
}
}
Ok(())
}
#[cfg(test)]
#[path = "./load_test.rs"]
mod load_test;