logic_eval/parse/
text.rs

1use super::{
2    CloseParenToken, CommaToken, DotToken, GlobalCx, HornToken, Ident, NegationToken,
3    OpenParenToken, Parse, ParseBuffer, VAR_PREFIX,
4    repr::{Clause, ClauseDataset, Expr, Term},
5};
6use crate::{Error, Result};
7use any_intern::Interned;
8use std::{borrow, fmt, ops};
9
10impl<'cx> Parse<'cx> for ClauseDataset<Name<'cx>> {
11    fn parse(buf: &mut ParseBuffer<'_>, gcx: &GlobalCx<'cx>) -> Result<Self> {
12        let clauses = buf.parse(gcx)?;
13        Ok(Self(clauses))
14    }
15}
16
17impl<'cx> Parse<'cx> for Vec<Clause<Name<'cx>>> {
18    fn parse(buf: &mut ParseBuffer<'_>, gcx: &GlobalCx<'cx>) -> Result<Self> {
19        let mut v = Vec::new();
20        while let Some((clause, moved_buf)) = buf.peek_parse::<Clause<Name>>(gcx) {
21            v.push(clause);
22            *buf = moved_buf;
23        }
24        Ok(v)
25    }
26}
27
28impl<'cx> Parse<'cx> for Clause<Name<'cx>> {
29    fn parse(buf: &mut ParseBuffer<'_>, gcx: &GlobalCx<'cx>) -> Result<Self> {
30        let head = buf.parse::<Term<Name>>(gcx)?;
31
32        let body = if let Some((_, mut body_buf)) = buf.peek_parse::<HornToken>(gcx) {
33            let dot = body_buf
34                .cur_text()
35                .find('.')
36                .ok_or(Error::from("clause must end with `.`"))?;
37            body_buf.end = body_buf.start + dot;
38            let body = body_buf.parse::<Expr<Name>>(gcx)?;
39
40            buf.start = body_buf.end + 1; // Next to the dot
41            Some(body)
42        } else {
43            let _ = buf.parse::<DotToken>(gcx)?;
44            None
45        };
46
47        Ok(Self { head, body })
48    }
49}
50
51// Precedence: `Paren ()` -> `Not \+` -> `And ,` -> `Or ;`
52impl<'cx> Expr<Name<'cx>> {
53    fn parse_or(buf: ParseBuffer<'_>, gcx: &GlobalCx<'cx>) -> Result<Self> {
54        Self::parse_by_delimiter(buf, gcx, ';', Self::parse_and, Self::Or)
55    }
56
57    fn parse_and(buf: ParseBuffer<'_>, gcx: &GlobalCx<'cx>) -> Result<Self> {
58        Self::parse_by_delimiter(buf, gcx, ',', Self::parse_not, Self::And)
59    }
60
61    fn parse_not(buf: ParseBuffer<'_>, gcx: &GlobalCx<'cx>) -> Result<Self> {
62        if let Some((_, moved_buf)) = buf.peek_parse::<NegationToken>(gcx) {
63            let inner = Self::parse_not(moved_buf, gcx)?;
64            Ok(Self::Not(Box::new(inner)))
65        } else {
66            Self::parse_paren(buf, gcx)
67        }
68    }
69
70    fn parse_paren(buf: ParseBuffer<'_>, gcx: &GlobalCx<'cx>) -> Result<Self> {
71        if let Some((_, mut moved_buf)) = buf.peek_parse::<OpenParenToken>(gcx) {
72            let r = moved_buf.cur_text().rfind(')').unwrap();
73            moved_buf.end = moved_buf.start + r;
74            moved_buf.parse::<Self>(gcx)
75        } else {
76            Self::parse_term(buf, gcx)
77        }
78    }
79
80    fn parse_term(mut buf: ParseBuffer<'_>, gcx: &GlobalCx<'cx>) -> Result<Self> {
81        if buf.cur_text().chars().all(|c: char| c.is_whitespace()) {
82            Err("expected a non-empty term expression".into())
83        } else {
84            buf.parse::<Term<Name>>(gcx).map(Self::Term)
85        }
86    }
87
88    fn parse_by_delimiter(
89        buf: ParseBuffer<'_>,
90        gcx: &GlobalCx<'cx>,
91        del: char,
92        parse_partial: fn(ParseBuffer<'_>, &GlobalCx<'cx>) -> Result<Self>,
93        wrap_vec: fn(Vec<Self>) -> Self,
94    ) -> Result<Self> {
95        let mut v = Vec::new();
96        let (mut l, mut r) = (buf.start, buf.start);
97        let mut open = 0;
98
99        for c in buf.cur_text().chars() {
100            if c == del && open == 0 {
101                let buf = ParseBuffer {
102                    text: buf.text,
103                    start: l,
104                    end: r,
105                };
106                let partial = parse_partial(buf, gcx)?;
107                v.push(partial);
108                l = r + c.len_utf8();
109            } else if c == '(' {
110                open += 1;
111            } else if c == ')' {
112                open -= 1;
113            }
114            r += c.len_utf8();
115        }
116
117        let buf = ParseBuffer {
118            text: buf.text,
119            start: l,
120            end: r,
121        };
122        let last = parse_partial(buf, gcx)?;
123
124        if !v.is_empty() {
125            v.push(last);
126            Ok(wrap_vec(v))
127        } else {
128            Ok(last)
129        }
130    }
131}
132
133impl<'cx> Parse<'cx> for Expr<Name<'cx>> {
134    fn parse(buf: &mut ParseBuffer<'_>, gcx: &GlobalCx<'cx>) -> Result<Self> {
135        // The buffer range is not being moved by this call.
136        Self::parse_or(*buf, gcx)
137    }
138}
139
140impl<'cx> Term<Name<'cx>> {
141    fn parse_args(
142        buf: &mut ParseBuffer<'_>,
143        gcx: &GlobalCx<'cx>,
144    ) -> Result<Box<[Term<Name<'cx>>]>> {
145        let mut open = 0;
146        while let Some((_, moved_buf)) = buf.peek_parse::<OpenParenToken>(gcx) {
147            *buf = moved_buf;
148            open += 1;
149        }
150
151        if open == 0 {
152            return Ok([].into());
153        }
154
155        let mut args = Vec::new();
156        let mut well_seperated = true;
157        loop {
158            if let Some((_, moved_buf)) = buf.peek_parse::<CloseParenToken>(gcx) {
159                *buf = moved_buf;
160                open -= 1;
161                break;
162            }
163
164            if !well_seperated {
165                return Err(format!("expected `,` from {}", buf.cur_text()).into());
166            }
167
168            let arg = buf.parse::<Term<Name>>(gcx)?;
169            args.push(arg);
170
171            let comma = buf.parse::<CommaToken>(gcx);
172            well_seperated = comma.is_ok();
173        }
174
175        for _ in 0..open {
176            buf.parse::<CloseParenToken>(gcx)?;
177        }
178
179        Ok(args.into())
180    }
181}
182
183impl<'cx> Parse<'cx> for Term<Name<'cx>> {
184    fn parse(buf: &mut ParseBuffer<'_>, gcx: &GlobalCx<'cx>) -> Result<Self> {
185        let functor = Name::parse(buf, gcx)?;
186        let args = Self::parse_args(buf, gcx)?;
187        Ok(Self { functor, args })
188    }
189}
190
191#[derive(Clone, PartialEq, Eq, Hash)]
192pub struct Name<'cx>(Interned<'cx, str>); // Non-empty string
193
194impl<'cx> Name<'cx> {
195    pub(crate) fn create(gcx: &GlobalCx<'cx>, s: &str) -> Self {
196        debug_assert!(!s.is_empty());
197
198        let interned = gcx.intern_str(s);
199        Self(interned)
200    }
201
202    pub(crate) fn is_variable(&self) -> bool {
203        let first = self.0.chars().next().unwrap();
204        first == VAR_PREFIX // btw, prolog style is `is_uppercase() or '_'`
205    }
206}
207
208impl<'cx> Parse<'cx> for Name<'cx> {
209    fn parse(buf: &mut ParseBuffer<'_>, gcx: &GlobalCx<'cx>) -> Result<Self> {
210        let ident = buf.parse::<Ident>(gcx)?;
211        let interned = gcx.intern_str(ident.to_text(buf.text));
212        debug_assert!(!interned.is_empty());
213        Ok(Self(interned))
214    }
215}
216
217impl fmt::Display for Name<'_> {
218    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
219        (**self).fmt(f)
220    }
221}
222
223impl fmt::Debug for Name<'_> {
224    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
225        (**self).fmt(f)
226    }
227}
228
229impl<'cx> ops::Deref for Name<'cx> {
230    type Target = Interned<'cx, str>;
231
232    fn deref(&self) -> &Self::Target {
233        &self.0
234    }
235}
236
237impl AsRef<str> for Name<'_> {
238    fn as_ref(&self) -> &str {
239        self
240    }
241}
242
243impl borrow::Borrow<str> for Name<'_> {
244    fn borrow(&self) -> &str {
245        self
246    }
247}