1use std::sync::Arc;
2
3use lalrpop_util::{lalrpop_mod, ParseError};
4
5use super::{
6 error::{self, PolarResult},
7 lexer::{self, Lexer, Token},
8 resource_block::Production,
9 rules::*,
10 sources::Source,
11 terms::*,
12};
13
14pub enum ValueOrLogical {
16 Value(Term),
17 Logical(Term),
18 Either(Term),
19}
20
21lalrpop_mod!(
22 #[allow(clippy::all, dead_code, unused_imports, unused_mut)]
23 polar
24);
25
26#[derive(Clone, Debug, PartialEq)]
27pub enum Line {
28 Rule(Rule),
29 RuleType(Rule),
30 Query(Term),
31 ResourceBlock {
32 keyword: Option<Term>,
33 resource: Term,
34 productions: Vec<Production>,
35 },
36}
37
38fn lalrpop_error_to_polar_error(
39 e: ParseError<usize, lexer::Token, error::ParseErrorKind>,
40 source: Arc<Source>,
41) -> error::PolarError {
42 let kind = match e {
43 ParseError::InvalidToken { location: loc } => error::ParseErrorKind::InvalidToken { loc },
44 ParseError::UnrecognizedEOF { location: loc, .. } => {
45 error::ParseErrorKind::UnrecognizedEOF { loc }
46 }
47 ParseError::UnrecognizedToken {
48 token: (loc, t, _), ..
49 } => match t {
50 Token::Debug | Token::Cut | Token::In | Token::New => {
51 error::ParseErrorKind::ReservedWord {
52 token: t.to_string(),
53 loc,
54 }
55 }
56 _ => error::ParseErrorKind::UnrecognizedToken {
57 token: t.to_string(),
58 loc,
59 },
60 },
61 ParseError::ExtraToken { token: (loc, t, _) } => error::ParseErrorKind::ExtraToken {
62 token: t.to_string(),
63 loc,
64 },
65 ParseError::User { error } => error,
66 };
67 error::ParseError { source, kind }.into()
68}
69
70pub fn parse_lines(source: Source) -> PolarResult<Vec<Line>> {
71 let source = Arc::new(source);
72 polar::LinesParser::new()
73 .parse(&source, Lexer::new(&source.src))
74 .map_err(|e| lalrpop_error_to_polar_error(e, source))
75}
76
77pub fn parse_query(query: &str) -> PolarResult<Term> {
78 let source = Arc::new(Source::new(query));
79 polar::TermParser::new()
80 .parse(&source, Lexer::new(query))
81 .map_err(|e| lalrpop_error_to_polar_error(e, source))
82}
83
84#[cfg(test)]
85pub fn parse_rules(rules: &str) -> PolarResult<Vec<Rule>> {
86 let source = Arc::new(Source::new(rules));
87 polar::RulesParser::new()
88 .parse(&source, Lexer::new(rules))
89 .map_err(|e| lalrpop_error_to_polar_error(e, source))
90}
91
92#[cfg(test)]
93mod tests {
94 use super::*;
95 use crate::error::ParseErrorKind::*;
96 use pretty_assertions::assert_eq;
97
98 #[track_caller]
99 fn parse_term(src: &str) -> Term {
100 super::parse_query(src).unwrap()
101 }
102
103 #[track_caller]
104 fn parse_term_error(src: &str) -> error::ParseErrorKind {
105 super::parse_query(src).unwrap_err().unwrap_parse()
106 }
107
108 #[track_caller]
109 fn parse_rule(src: &str) -> Rule {
110 super::parse_rules(src).unwrap().pop().unwrap()
111 }
112
113 #[track_caller]
114 fn parse_lines(src: &str) -> Vec<Line> {
115 super::parse_lines(Source::new(src)).unwrap()
116 }
117
118 #[test]
119 fn test_dot_lookups() {
120 let exp = parse_term("a.b");
121 assert_eq!(exp, term!(op!(Dot, term!(sym!("a")), term!("b"))));
122 }
123
124 #[test]
125 fn try_it_with_macros() {
126 let int = parse_term(" 123");
127 assert_eq!(int, term!(123));
128 assert_eq!(int.parsed_context().map(|context| context.left), Some(1));
129 let s = parse_term(r#""string literal""#);
130 assert_eq!(s, term!("string literal"));
131
132 let t = parse_term("true");
133 assert_eq!(t, term!(true));
134
135 let sym = parse_term("foo_qwe");
136 assert_eq!(sym, term!(sym!("foo_qwe")));
137
138 let l = parse_term("[foo, bar, baz]");
139 assert_eq!(l, term!([sym!("foo"), sym!("bar"), sym!("baz")]));
140
141 super::parse_rules(r#"bar(a, c) if foo(a, b(c), "d")"#).expect_err("parse error");
142
143 let exp2 = parse_term("foo.a(b)");
144 assert_eq!(
145 exp2,
146 term!(op!(Dot, term!(sym!("foo")), term!(call!("a", [sym!("b")])))),
147 "{}",
148 exp2
149 );
150 let rule = parse_rule("f(x) if g(x);");
151 assert_eq!(rule, rule!("f", [sym!("x")] => call!("g", [sym!("x")])));
152 let rule = parse_rule("f(x);");
153 assert_eq!(rule, rule!("f", [sym!("x")]));
154 }
155
156 #[test]
157 fn parse_booleans() {
158 assert_eq!(parse_term("true"), term!(true));
159 assert_eq!(parse_term("false"), term!(false));
160 }
161
162 #[test]
163 fn parse_integers() {
164 assert_eq!(parse_term("123"), term!(123));
165 assert_eq!(parse_term("0"), term!(0));
166 assert_eq!(parse_term("+123"), term!(123));
167 assert_eq!(parse_term("-123"), term!(-123));
168 }
169
170 #[test]
171 fn parse_floats() {
172 assert_eq!(parse_term("0.123"), term!(0.123));
173 assert_eq!(parse_term("1.234"), term!(1.234));
174 assert_eq!(parse_term("+1.234"), term!(1.234));
175 assert_eq!(parse_term("-1.234"), term!(-1.234));
176 assert_eq!(parse_term("-1.234e-56"), term!(-1.234e-56));
177 assert_eq!(parse_term("-1.234e56"), term!(-1.234e56));
178 assert_eq!(parse_term("inf"), term!(f64::INFINITY));
179 assert_eq!(parse_term("-inf"), term!(f64::NEG_INFINITY));
180 assert!(
181 matches!(parse_term("nan").value(), Value::Number(crate::numerics::Numeric::Float(f)) if f.is_nan())
182 );
183 }
184
185 #[test]
186 fn test_parse_specializers() {
187 let rule = parse_rule("f(x: 1);");
188 assert_eq!(rule, rule!("f", ["x"; 1]));
189
190 let rule = parse_rule("f(x: 1, y: [x]) if y = 2;");
191 assert_eq!(
192 rule,
193 rule!("f", ["x" ; 1 , "y" ; value!([sym!("x")])] => op!(Unify, term!(sym!("y")), term!(2)))
194 );
195
196 let rule = parse_rule("f(x: y);");
198 assert_eq!(rule, rule!("f", ["x"; value!(instance!("y"))]));
199 }
200
201 #[test]
202 fn test_parse_file() {
203 let f = "a(1);b(2);c(3);";
204 let results = super::parse_rules(f).unwrap();
205 assert_eq!(results[0].to_string(), "a(1);");
206 assert_eq!(results[1].to_string(), "b(2);");
207 assert_eq!(results[2].to_string(), "c(3);");
208 }
209
210 #[test]
211 fn test_parse_line() {
212 let kb = "f(x) if x = 1;";
213 let line = parse_lines(kb);
214 assert_eq!(
215 line[0],
216 Line::Rule(rule!("f", [sym!("x")] => op!(Unify, term!(sym!("x")), term!(1))))
217 );
218 let f = "?= f(1);";
219 let line = parse_lines(f);
220
221 assert_eq!(line[0], Line::Query(term!(call!("f", [1]))));
222
223 let rule_type = "type f(x: String);";
224 let line = parse_lines(rule_type);
225 assert_eq!(
226 line[0],
227 Line::RuleType(rule!("f", ["x"; value!(instance!("String"))]))
228 );
229 }
230
231 #[test]
232 fn test_rule_type_error() {
233 let rule_type = r#"type f(x: String) if x = "bad";"#;
234 super::parse_lines(Source::new(rule_type)).unwrap_err();
235 }
236
237 #[test]
238 fn test_parse_new() {
239 let f = "a(x) if x = new Foo(a: 1);";
240 let results = super::parse_rules(f).unwrap();
241 assert_eq!(results[0].to_string(), "a(x) if x = new Foo(a: 1);");
242 }
243
244 #[test]
245 fn test_parse_new_boa_constructor() {
246 let f = "a(x) if x = new Foo(1, 2);";
247 let results = super::parse_rules(f).unwrap();
248 assert_eq!(results[0].to_string(), "a(x) if x = new Foo(1, 2);");
249
250 let f = "a(x) if x = new Foo(1,);";
252 super::parse_rules(f).expect_err("parse error");
253 }
254
255 #[test]
256 fn test_parse_new_mixed_args() {
257 let f = "a(x) if x = new Foo(1, 2, bar: 3, baz:4);";
258 let results = super::parse_rules(f).unwrap();
259 assert_eq!(
260 results[0].to_string(),
261 "a(x) if x = new Foo(1, 2, bar: 3, baz: 4);"
262 );
263 let f = "a(x) if x = new Foo(bar: 3, baz: 4);";
264 let results = super::parse_rules(f).unwrap();
265 assert_eq!(
266 results[0].to_string(),
267 "a(x) if x = new Foo(bar: 3, baz: 4);"
268 );
269
270 let f = "a(x) if x = new Foo(bar: 3, baz: 4, 1, 2);";
271 super::parse_rules(f).expect_err("parse error");
272
273 let f = "a(x) if f(x: 1)";
275 super::parse_rules(f).expect_err("parse error");
276 let f = "a(x) if x.f(x: 1)";
277 super::parse_rules(f).expect_err("parse error");
278 }
279
280 #[test]
281 fn test_parse_matches() {
282 let term = parse_term("{} matches {}");
283 assert_eq!(term.to_string(), "{} matches {}");
284 let term = parse_term("{x: 1} matches {}");
285 assert_eq!(term.to_string(), "{x: 1} matches {}");
286 }
287
288 #[test]
289 fn test_parse_rest_vars() {
290 let q = "[1, 2, *x] = [*rest]";
291 assert_eq!(parse_term(q).to_string(), q);
292
293 let e = parse_term_error("[1, 2, 3] = [*rest, 3]");
294 assert!(matches!(e, UnrecognizedToken { .. }));
295
296 let e = parse_term_error("[1, 2, *3] = [*rest]");
297 assert!(matches!(e, UnrecognizedToken { .. }));
298
299 let e = parse_term_error("[1, *x, *y] = [*rest]");
300 assert!(matches!(e, UnrecognizedToken { .. }));
301
302 let q = "[1, 2, 3] matches [1, 2, 3]";
303 assert_eq!(parse_term(q).to_string(), q, "{} -- {}", q, parse_term(q));
304
305 let q = "[1, 2, 3] matches [1, *rest]";
306 assert_eq!(parse_term(q).to_string(), q, "{} -- {}", q, parse_term(q));
307 }
308
309 #[test]
310 fn test_primitive_methods() {
311 let q = r#""abc".startswith("a")"#;
312 assert_eq!(
313 parse_term(q),
314 term!(op!(Dot, term!("abc"), term!(call!("startswith", ["a"])))),
315 );
316
317 let q = r#"x.("invalid-key")"#;
318 assert_eq!(
319 parse_term(q),
320 term!(op!(Dot, term!(sym!("x")), term!("invalid-key"))),
321 );
322 }
323
324 #[test]
325 fn test_catching_wrong_types() {
326 for bad_query in &[
327 "f(x=1)",
328 "x in [1, 2] < 2",
329 "{x: 1 < 2}",
330 "{x: 1 < 2}",
331 "not 1",
332 "1 and 2",
333 "1 + print(\"x\")",
334 "forall([1, 2, 3], x < 1)",
335 "x = (1 or 2)",
336 "x = (1 = 2)",
337 "foo.bar(x or y)",
338 "foo.bar(z: x or y)",
339 "x = y = z",
340 "x = y = 1",
341 "x = 1 = z",
342 "1 = y = z",
343 "x = (1 and 2)",
344 "(1 or 2) = x",
345 "x = (not x)",
346 "y matches z = x",
347 ] {
348 assert!(matches!(parse_term_error(bad_query), WrongValueType { .. }));
349 }
350 }
351
352 #[test]
353 fn trailing_commas() {
354 let q = "{a: 1,}";
355 let dict = term!(btreemap! { sym!("a") => term!(1)});
356 assert_eq!(parse_term(q), dict);
357
358 let q = "[1, 2,]";
359 let list = term!([1, 2]);
360 assert_eq!(parse_term(q), list);
361
362 assert_eq!(
363 parse_term("{a: 1,} = [1, 2,]"),
364 term!(op!(Unify, dict, list))
365 );
366 }
367
368 #[test]
369 fn duplicate_keys() {
370 let q = "{a: 1, a: 2}";
371 assert!(matches!(parse_term_error(q), DuplicateKey { .. }));
372 }
373}