Files
picolog/src/ast.rs
2026-02-12 20:59:45 +01:00

189 lines
4.0 KiB
Rust

use owo_colors::{OwoColorize, colors::css::Gray};
use std::fmt::Display;
use crate::domain::Domain;
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct Variable(pub String, pub Option<usize>);
#[derive(Clone, Debug)]
pub struct Module
{
pub clauses: Vec<Clause>,
}
#[derive(Clone, Debug)]
pub struct Clause
{
pub head: Predicate,
pub body: Option<Body>,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum Body
{
Term(Predicate),
And(Vec<Body>),
Or(Vec<Body>),
}
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum Predicate
{
Variable(Variable), // Upercase variable like X
Fixed(Functor, Vec<Predicate>),
Domain(Domain),
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum Functor
{
Operator(Operator),
Functor(String),
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Operator
{
pub op: String,
pub precedence: usize,
pub op_type: OperatorType,
}
impl Operator
{
pub fn new(op: String, precedence: usize, op_type: OperatorType) -> Self
{
Self {
op,
precedence,
op_type,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum OperatorType
{
Prefix,
Postfix,
LeftInfix,
RightInfix,
}
impl Display for Body
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
{
match self
{
Body::Term(predicate) => write!(f, "{}", predicate),
Body::And(items) | Body::Or(items) =>
{
let len = items.len();
for (i, item) in items.iter().enumerate()
{
write!(f, "{}", item)?;
if i != len - 1
{
write!(f, ",")?;
}
}
Ok(())
}
}
}
}
impl Display for Variable
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
{
write!(f, "{}", self.0)?;
if let Some(num) = self.1
{
write!(f, "{}", format!("[{}]", num).fg::<Gray>())?;
}
Ok(())
}
}
impl Display for Predicate
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
{
match self
{
Predicate::Variable(variable) => write!(f, "{}", variable),
Predicate::Fixed(name, predicates) =>
{
write!(f, "{}", name)?;
if !predicates.is_empty()
{
write!(f, "(")?;
let len = predicates.len();
for (i, predicate) in predicates.iter().enumerate()
{
write!(f, "{}", predicate)?;
if i != len - 1
{
write!(f, ", ")?;
}
}
write!(f, ")")
}
else
{
Ok(())
}
}
Predicate::Domain(domain) => write!(f, "{domain}"),
}
}
}
impl Display for Clause
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
{
write!(f, "{}", self.head)?;
self.body
.as_ref()
.map_or_else(|| Ok(()), |body| write!(f, ":- {}", body))?;
write!(f, ".")
}
}
impl Display for Module
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
{
for clause in self.clauses.iter()
{
writeln!(f, "{}", clause)?;
}
Ok(())
}
}
impl Display for Functor
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
{
match self
{
Functor::Operator(op) => write!(f, "{}", op),
Functor::Functor(name) => write!(f, "{}", name),
}
}
}
impl Display for Operator
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
{
write!(f, "{}", self.op)
}
}