use crate::pretty_print::{sealed, PrettyRenderer};
use crate::types::{Domain, DomainConstraintsDef};
use crate::visitor::{Accept, Visitor};
use pretty::RcDoc;
impl sealed::Sealed for Domain {}
impl sealed::Sealed for DomainConstraintsDef {}
impl Visitor<DomainConstraintsDef, RcDoc<'static>> for PrettyRenderer {
fn visit(&self, value: &DomainConstraintsDef) -> RcDoc<'static> {
if value.value().is_empty() {
return RcDoc::nil();
}
value.value().accept(self)
}
}
impl Visitor<Domain, RcDoc<'static>> for PrettyRenderer {
fn visit(&self, value: &Domain) -> RcDoc<'static> {
let mut doc = RcDoc::text("(")
.append(RcDoc::text("define"))
.append(RcDoc::hardline())
.append(RcDoc::text("(domain "))
.append(value.name().accept(self))
.append(")");
if !value.extends().is_empty() {
doc = doc
.append(RcDoc::hardline())
.append(RcDoc::text("(:extends"))
.append(RcDoc::softline())
.append(RcDoc::intersperse(
value.extends().iter().map(|n| n.accept(self)),
RcDoc::softline(),
))
.nest(4)
.group()
.append(")");
}
if !value.requirements().is_empty() {
doc = doc.append(RcDoc::hardline()).append(self.section(
"requirements",
value.requirements().iter().map(|r| r.accept(self)),
));
}
if !value.types().is_empty() {
doc = doc
.append(RcDoc::hardline())
.append(RcDoc::text("(:types"))
.append(RcDoc::softline())
.append(value.types().accept(self))
.nest(4)
.group()
.append(")");
}
if !value.constants().is_empty() {
doc = doc
.append(RcDoc::hardline())
.append(RcDoc::text("(:constants"))
.append(RcDoc::softline())
.append(value.constants().accept(self))
.nest(4)
.group()
.append(")");
}
if !value.predicates().is_empty() {
doc = doc.append(RcDoc::hardline()).append(self.section(
"predicates",
value.predicates().iter().map(|p| p.accept(self)),
));
}
if !value.functions().is_empty() {
doc = doc.append(RcDoc::hardline()).append(self.section(
"functions",
value.functions().values().iter().map(|f| f.accept(self)),
));
}
if !value.constraints().is_empty() {
doc = doc
.append(RcDoc::hardline())
.append(self.section("constraints", [value.constraints().accept(self)]));
}
if !value.timeless().is_empty() {
doc = doc
.append(RcDoc::hardline())
.append(value.timeless().accept(self));
}
if !value.structure().is_empty() {
doc = doc
.append(RcDoc::hardline())
.append(value.structure().accept(self));
}
doc.append(RcDoc::hardline()).append(")").nest(2).group()
}
}
#[cfg(test)]
mod tests {
use crate::parsers::Parser;
use crate::pretty_print::Pretty;
use crate::types::{ConstraintGoalDefinition, DomainConstraintsDef};
#[test]
fn domain_basic() {
let input = r#"(define (domain test)
(:requirements :strips)
(:types block)
(:predicates (on ?x ?y - block))
)"#;
let domain = crate::Domain::from_str(input).unwrap();
let output = domain.pretty(80).to_string();
assert!(output.contains("(define"));
assert!(output.contains("(domain test)"));
}
#[test]
fn domain_with_extends() {
let input = r#"(define (domain child)
(:extends parent)
(:requirements :strips)
)"#;
let domain = crate::Domain::from_str(input).unwrap();
let output = domain.pretty(80).to_string();
assert!(output.contains("(:extends parent)"));
}
#[test]
fn domain_with_constants() {
let input = r#"(define (domain test)
(:requirements :strips)
(:constants c1 c2)
)"#;
let domain = crate::Domain::from_str(input).unwrap();
let output = domain.pretty(80).to_string();
assert!(output.contains("(:constants c1 c2)"));
}
#[test]
fn domain_with_functions() {
let input = r#"(define (domain test)
(:requirements :strips)
(:predicates (p ?x))
(:action a
:parameters (?x)
:precondition (and)
:effect (and)
)
)"#;
let domain = crate::Domain::from_str(input).unwrap();
let output = domain.pretty(80).to_string();
assert!(output.contains("(:action a"));
}
#[test]
fn domain_with_constraints() {
let input = r#"(define (domain test)
(:requirements :strips)
(:predicates (p))
(:action a
:parameters ()
:precondition (and)
:effect (and)
)
)"#;
let domain = crate::Domain::from_str(input).unwrap();
let output = domain.pretty(80).to_string();
assert!(output.contains("(:action a"));
}
#[test]
fn domain_with_timeless() {
let input = r#"(define (domain test)
(:requirements :strips)
(:predicates (p))
(:timeless (p))
)"#;
let domain = crate::Domain::from_str(input).unwrap();
let output = domain.pretty(80).to_string();
assert!(output.contains("(:timeless"));
}
#[test]
fn domain_with_structure() {
let input = r#"(define (domain test)
(:requirements :strips)
(:predicates (p))
(:action a
:parameters ()
:precondition (and)
:effect (and)
)
)"#;
let domain = crate::Domain::from_str(input).unwrap();
let output = domain.pretty(80).to_string();
assert!(output.contains("(:action"));
}
#[test]
fn domain_constraints_def_empty_nil() {
let dc = DomainConstraintsDef::new(ConstraintGoalDefinition::default());
let out = dc.pretty(80).to_string();
assert_eq!(out, "");
}
}