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; Some(body)
42 } else {
43 let _ = buf.parse::<DotToken>(gcx)?;
44 None
45 };
46
47 Ok(Self { head, body })
48 }
49}
50
51impl<'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 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>); impl<'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 }
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}