fall/
ast.rs

1use std::collections::{HashMap, HashSet};
2use std::fmt::{Display, Formatter, Result as FmtResult};
3use std::fs::File;
4use std::io::Read;
5use std::path::Path;
6use std::str::FromStr;
7use std::sync::Arc;
8
9use regex::Regex;
10
11use cst;
12use errors::LoadError;
13use util::gensym;
14
15/// A collection of rules or facts (as clauses).
16#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
17pub struct Rules(pub Vec<Clause>);
18
19impl Rules {
20    /// Loads from a file.
21    pub fn load_from(path: impl AsRef<Path>) -> Result<Rules, LoadError> {
22        let src = {
23            let mut f = File::open(path).map_err(LoadError::Io)?;
24            let mut buf = String::new();
25            f.read_to_string(&mut buf).map_err(LoadError::Io)?;
26            buf
27        };
28        src.parse().map_err(LoadError::Parse)
29    }
30}
31
32impl FromStr for Rules {
33    type Err = <cst::Rules as FromStr>::Err;
34    fn from_str(src: &str) -> Result<Rules, Self::Err> {
35        let cst = src.parse::<cst::Rules>()?;
36        let mut atoms = HashSet::new();
37        Ok(cst.to_ast(&mut atoms))
38    }
39}
40
41/// A single rule or fact.
42#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
43pub struct Clause(pub Lit, pub Vec<Lit>);
44
45impl Clause {
46    /// Replaces all variables in the clause with fresh ones.
47    pub fn freshen(&self) -> Clause {
48        let Clause(ref head, ref body) = *self;
49        let mut vars = HashMap::new();
50        let head = head.freshen_helper(&mut vars);
51        let body = body
52            .iter()
53            .map(|lit| lit.freshen_helper(&mut vars))
54            .collect::<Vec<_>>();
55        Clause(head, body)
56    }
57}
58
59impl Display for Clause {
60    fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
61        let Clause(ref head, ref body) = *self;
62
63        write!(fmt, "{}", head)?;
64        let mut first = true;
65        for lit in body {
66            let prefix = if first {
67                first = false;
68                " :- "
69            } else {
70                ", "
71            };
72            write!(fmt, "{}{}", prefix, lit)?;
73        }
74        write!(fmt, ".")
75    }
76}
77
78/// A term, e.g. `even(X)`, `30`, `foo`, or `Bar`.
79#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
80pub enum Term {
81    /// A literal value, e.g. `foo`, `bar(1, 2)`, or `baz(X, a, X)`.
82    Lit(Lit),
83
84    /// A numeric literal, e.g. `0`, `42`, or `137`.
85    Num(u32),
86
87    /// A variable. Each variable is globally unified against, so the actual resolution procedure
88    /// will "freshen" a clause before running it by replacing its variables with fresh ones.
89    Var(usize),
90}
91
92impl Term {
93    fn freshen_helper(&self, vars: &mut HashMap<usize, usize>) -> Arc<Term> {
94        Arc::new(match *self {
95            Term::Lit(ref l) => Term::Lit(l.freshen_helper(vars)),
96            Term::Num(n) => Term::Num(n),
97            Term::Var(v) => Term::Var(*vars.entry(v).or_insert_with(gensym)),
98        })
99    }
100
101    /// Returns a unique `Var`.
102    pub fn gensym() -> Arc<Term> {
103        Arc::new(Term::Var(gensym()))
104    }
105}
106
107impl Display for Term {
108    fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
109        match *self {
110            Term::Lit(ref l) => write!(fmt, "{}", l),
111            Term::Num(n) => write!(fmt, "{}", n),
112            Term::Var(v) => write!(fmt, "_{}", v),
113        }
114    }
115}
116
117/// A literal value, e.g. `foo`, `bar(1, 2)`, or `baz(X, a, X)`.
118#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
119pub struct Lit(pub Arc<str>, pub Vec<Arc<Term>>);
120
121impl Lit {
122    fn freshen_helper(&self, vars: &mut HashMap<usize, usize>) -> Lit {
123        let Lit(ref name, ref args) = *self;
124        let args = args
125            .iter()
126            .map(|a| a.freshen_helper(vars))
127            .collect::<Vec<_>>();
128        Lit(name.clone(), args)
129    }
130
131    /// Returns the name and arity of the literal.
132    pub fn functor(&self) -> (Arc<str>, usize) {
133        (self.0.clone(), self.1.len())
134    }
135
136    /// Returns the name and arity of the literal.
137    pub fn functor_b(&self) -> (&str, usize) {
138        (&*self.0, self.1.len())
139    }
140}
141
142impl Display for Lit {
143    fn fmt(&self, fmt: &mut Formatter) -> FmtResult {
144        lazy_static! {
145            static ref UNQUOTED_ATOM: Regex = Regex::new("[a-z.][A-Za-z_.]*").unwrap();
146        }
147
148        let Lit(ref name, ref args) = *self;
149        if UNQUOTED_ATOM.is_match(name) {
150            write!(fmt, "{}", name)?;
151        } else if name.contains('\'') {
152            write!(fmt, "\"{}\"", name)?;
153        } else {
154            write!(fmt, "'{}'", name)?;
155        }
156
157        if !args.is_empty() {
158            let mut first = true;
159            for arg in args {
160                let prefix = if first {
161                    first = false;
162                    "("
163                } else {
164                    ", "
165                };
166                write!(fmt, "{}{}", prefix, arg)?;
167            }
168            write!(fmt, ")")?;
169        }
170
171        Ok(())
172    }
173}