1use xlog_core::Result;
4use xlog_ir::{
5 EirAtom, EirBodyLiteral, EirConstraint, EirEpistemicLiteral, EirEpistemicMode, EirEpistemicOp,
6 EirProgram, EirRule, EirTerm,
7};
8
9use crate::ast::{
10 AggOp, Atom, BodyLiteral, Constraint as AstConstraint, EpistemicMode, EpistemicOp, Program,
11 Rule as AstRule, Term,
12};
13
14pub fn build_eir(program: &Program) -> Result<EirProgram> {
16 Ok(EirProgram {
17 mode: convert_mode(program.directives.epistemic_mode_or_default()),
18 rules: program.rules.iter().map(convert_rule).collect(),
19 constraints: program.constraints.iter().map(convert_constraint).collect(),
20 })
21}
22
23fn convert_constraint(constraint: &AstConstraint) -> EirConstraint {
24 EirConstraint {
25 body: constraint.body.iter().map(convert_body_literal).collect(),
26 }
27}
28
29fn convert_rule(rule: &AstRule) -> EirRule {
30 EirRule {
31 head: convert_atom(&rule.head),
32 body: rule.body.iter().map(convert_body_literal).collect(),
33 }
34}
35
36fn convert_body_literal(lit: &BodyLiteral) -> EirBodyLiteral {
37 match lit {
38 BodyLiteral::Positive(atom) => EirBodyLiteral::Relational {
39 negated: false,
40 atom: convert_atom(atom),
41 },
42 BodyLiteral::Negated(atom) => EirBodyLiteral::Relational {
43 negated: true,
44 atom: convert_atom(atom),
45 },
46 BodyLiteral::Epistemic(lit) => EirBodyLiteral::Epistemic(EirEpistemicLiteral {
47 op: convert_op(lit.op),
48 negated: lit.negated,
49 atom: convert_atom(&lit.atom),
50 }),
51 BodyLiteral::Comparison(_) => EirBodyLiteral::Constraint,
52 BodyLiteral::IsExpr(_) => EirBodyLiteral::Binding,
53 BodyLiteral::Univ(_) => EirBodyLiteral::Binding,
54 }
55}
56
57fn convert_atom(atom: &Atom) -> EirAtom {
58 EirAtom {
59 predicate: atom.predicate.clone(),
60 arity: atom.arity(),
61 terms: atom.terms.iter().map(convert_term).collect(),
62 }
63}
64
65fn convert_term(term: &Term) -> EirTerm {
66 match term {
67 Term::Variable(name) => EirTerm::Variable(name.clone()),
68 Term::Anonymous => EirTerm::Anonymous,
69 Term::Integer(value) => EirTerm::Integer(*value),
70 Term::Float(value) => EirTerm::FloatBits(value.to_bits()),
71 Term::String(value) => EirTerm::String(value.clone()),
72 Term::Symbol(id) => EirTerm::Symbol(*id),
73 Term::List(items) => EirTerm::List(items.iter().map(convert_term).collect()),
74 Term::Cons { head, tail } => EirTerm::Cons {
75 head: Box::new(convert_term(head)),
76 tail: Box::new(convert_term(tail)),
77 },
78 Term::Compound { functor, args } => EirTerm::Compound {
79 functor: functor.clone(),
80 args: args.iter().map(convert_term).collect(),
81 },
82 Term::PredRef(name) => EirTerm::PredRef(name.clone()),
83 Term::Aggregate(agg) => EirTerm::Aggregate {
84 op: convert_agg_op(agg.op).to_string(),
85 variable: agg.variable.clone(),
86 },
87 }
88}
89
90fn convert_agg_op(op: AggOp) -> &'static str {
91 match op {
92 AggOp::Count => "count",
93 AggOp::Sum => "sum",
94 AggOp::Min => "min",
95 AggOp::Max => "max",
96 AggOp::LogSumExp => "logsumexp",
97 }
98}
99
100fn convert_mode(mode: EpistemicMode) -> EirEpistemicMode {
101 match mode {
102 EpistemicMode::G91 => EirEpistemicMode::G91,
103 EpistemicMode::Faeel => EirEpistemicMode::Faeel,
104 }
105}
106
107fn convert_op(op: EpistemicOp) -> EirEpistemicOp {
108 match op {
109 EpistemicOp::Know => EirEpistemicOp::Know,
110 EpistemicOp::Possible => EirEpistemicOp::Possible,
111 }
112}