use std::path::Path; use winnow::Parser; use winnow::Result; use winnow::ascii::alphanumeric0; use winnow::ascii::multispace0; use winnow::combinator::alt; use winnow::combinator::delimited; use winnow::combinator::opt; use winnow::combinator::separated; use winnow::combinator::seq; use winnow::error::ContextError; use crate::ast::Body; use crate::ast::Clause; use crate::ast::Module; use crate::ast::Predicate; use crate::ast::Variable; pub fn predicate_parse(input: &mut &str) -> Result { let ident = alphanumeric0.parse_next(input)?; // Check if output is a variable if ident.chars().next().is_some_and(|char| char.is_uppercase()) { Ok(Predicate::Variable(Variable(String::from(ident), None))) } else { let arguments = delimited( ("(", multispace0), separated(1.., predicate_parse, (multispace0, ",", multispace0)), (multispace0, ")"), ) .parse_next(input) .unwrap_or(Vec::new()); Ok(Predicate::Fixed(String::from(ident), arguments)) } } fn body_parse_or(input: &mut &str) -> Result { separated( 1.., alt(( delimited("(", body_parse, ")"), predicate_parse.map(Body::Term), )), (multispace0, ";", multispace0), ) .map(Body::Or) .parse_next(input) } pub fn body_parse(input: &mut &str) -> Result { // Parse and separated(1.., body_parse_or, (multispace0, ",", multispace0)) .map(Body::And) .parse_next(input) } pub fn clause_parse(input: &mut &str) -> Result { seq! { Clause { head: predicate_parse, body: opt((multispace0, ":-", multispace0, body_parse).map(|(_, _, _, b)| b)), _: multispace0, _: "." } } .parse_next(input) } pub fn module_parse(input: &mut &str) -> Result { let _: Result<&str, ContextError> = multispace0.parse_next(input); separated(0.., clause_parse, multispace0) .map(|clauses| Module { clauses }) .parse_next(input) } impl From for Module where T: AsRef, { fn from(value: T) -> Self { let mut str: &str = value.as_ref(); module_parse.parse_next(&mut str).unwrap() } } impl Module { pub fn parse_from_file>(path: P) -> Self { std::fs::read_to_string(path).unwrap().into() } } impl From for Predicate where T: AsRef, { fn from(value: T) -> Self { let mut str: &str = value.as_ref(); predicate_parse.parse_next(&mut str).unwrap() } } impl From for Body where T: AsRef, { fn from(value: T) -> Self { let mut str: &str = value.as_ref(); body_parse.parse_next(&mut str).unwrap() } }