Files
picolog/src/parsing.rs

126 lines
2.8 KiB
Rust

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<Predicate>
{
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<Body>
{
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<Body>
{
// Parse and
separated(1.., body_parse_or, (multispace0, ",", multispace0))
.map(Body::And)
.parse_next(input)
}
pub fn clause_parse(input: &mut &str) -> Result<Clause>
{
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<Module>
{
let _: Result<&str, ContextError> = multispace0.parse_next(input);
separated(0.., clause_parse, multispace0)
.map(|clauses| Module { clauses })
.parse_next(input)
}
impl<T> From<T> for Module
where
T: AsRef<str>,
{
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<P: AsRef<Path>>(path: P) -> Self
{
std::fs::read_to_string(path).unwrap().into()
}
}
impl<T> From<T> for Predicate
where
T: AsRef<str>,
{
fn from(value: T) -> Self
{
let mut str: &str = value.as_ref();
predicate_parse.parse_next(&mut str).unwrap()
}
}
impl<T> From<T> for Body
where
T: AsRef<str>,
{
fn from(value: T) -> Self
{
let mut str: &str = value.as_ref();
body_parse.parse_next(&mut str).unwrap()
}
}