pub mod lexer;
pub mod lowering;
pub mod parser;
pub use lowering::{lower_rule_set, LoweringError};
pub use parser::{JrlParseError, JrlRuleSet};
use crate::Rule;
pub fn parse_jrl(input: &str) -> Result<JrlRuleSet, JrlParseError> {
let tokens = lexer::Lexer::tokenize(input).map_err(|e| JrlParseError {
message: format!("lex error: {}", e),
token_index: 0,
})?;
parser::parse(&tokens)
}
pub fn parse_and_lower(input: &str) -> Result<Vec<Rule>, LoweringError> {
let rule_set = parse_jrl(input)?;
lower_rule_set(&rule_set)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_jrl_empty_returns_empty() {
let rs = parse_jrl("").expect("empty input should succeed");
assert!(rs.rules.is_empty());
}
#[test]
fn test_parse_and_lower_roundtrip() {
let src = "[r: (?x rdf:type rdfs:Class) -> (?x rdf:type owl:Class)]";
let rules = parse_and_lower(src).expect("should succeed");
assert_eq!(rules.len(), 1);
}
#[test]
fn test_parse_jrl_retains_prefix_map() {
let src = "@prefix foo: <http://foo.org/> .\n[r: (?x foo:bar ?y) -> (?x foo:baz ?y)]";
let rs = parse_jrl(src).expect("should parse");
assert!(rs.prefixes.contains_key("foo"));
}
#[test]
fn test_parse_and_lower_with_prefixes() {
let src = "@prefix ex: <http://example.org/> .\n[rule1: (?a ex:p ?b) -> (?a ex:q ?b)]";
let rules = parse_and_lower(src).expect("should succeed");
assert_eq!(rules.len(), 1);
assert_eq!(rules[0].name, "rule1");
}
}