Skip to main content

surql_parser/upstream/syn/parser/
expression.rs

1//! This module defines the pratt parser for operators.
2use super::enter_query_recursion;
3use super::mac::unexpected;
4use crate::compat::types::PublicDuration;
5use crate::upstream::sql::operator::{
6	BindingPower, BooleanOperator, MatchesOperator, NearestNeighbor,
7};
8use crate::upstream::sql::{BinaryOperator, Expr, Literal, Part, PostfixOperator, PrefixOperator};
9use crate::upstream::syn::error::bail;
10use crate::upstream::syn::lexer::compound::Numeric;
11use crate::upstream::syn::parser::mac::expected;
12use crate::upstream::syn::parser::{ParseResult, Parser};
13use crate::upstream::syn::token::{Span, Token, TokenKind, t};
14use reblessive::Stk;
15use surrealdb_types::ToSql;
16impl Parser<'_> {
17	/// Parse a generic expression without triggering the query depth and
18	/// setting table_as_field.
19	///
20	/// Meant to be used when parsing an expression the first time to avoid
21	/// having the depth limit be lowered unnecessarily.
22	pub async fn parse_expr_start(&mut self, stk: &mut Stk) -> ParseResult<Expr> {
23		self.table_as_field = true;
24		self.pratt_parse_expr(stk, BindingPower::Base).await
25	}
26	/// Parsers a generic value.
27	///
28	/// A generic loose ident like `foo` in for example `foo.bar` can be two
29	/// different values depending on context: a table or a field the current
30	/// document. This function parses loose idents as a table, see
31	/// [`parse_expr_field`] for parsing loose idents as fields
32	pub async fn parse_expr_table(&mut self, stk: &mut Stk) -> ParseResult<Expr> {
33		let old = self.table_as_field;
34		self.table_as_field = false;
35		let res = enter_query_recursion!(
36			this = self => { this.pratt_parse_expr(stk, BindingPower::Base). await }
37		);
38		self.table_as_field = old;
39		res
40	}
41	/// Parsers a generic value.
42	///
43	/// A generic loose ident like `foo` in for example `foo.bar` can be two
44	/// different values depending on context: a table or a field the current
45	/// document. This function parses loose idents as a field, see
46	/// [`parse_expr_table`] for parsing loose idents as table
47	pub async fn parse_expr_field(&mut self, stk: &mut Stk) -> ParseResult<Expr> {
48		let old = self.table_as_field;
49		self.table_as_field = true;
50		let res = enter_query_recursion!(
51			this = self => { this.pratt_parse_expr(stk, BindingPower::Base). await }
52		);
53		self.table_as_field = old;
54		res
55	}
56	/// Parsers a generic value.
57	///
58	/// Inherits how loose identifiers are parsed from it's caller.
59	pub(super) async fn parse_expr_inherit(&mut self, stk: &mut Stk) -> ParseResult<Expr> {
60		enter_query_recursion!(
61			this = self => { this.pratt_parse_expr(stk, BindingPower::Base). await }
62		)
63	}
64	/// Returns the binding power of an infix operator.
65	///
66	/// Binding power is the opposite of precedence: a higher binding power
67	/// means that a token is more like to operate directly on it's neighbours.
68	/// Example `*` has a higher binding power than `-` resulting in 1 - 2 * 3
69	/// being parsed as 1 - (2 * 3).
70	///
71	/// All operators in SurrealQL which are parsed by the functions in this
72	/// module are left associative or have no defined associativity.
73	fn infix_binding_power(&mut self, token: TokenKind) -> Option<BindingPower> {
74		match token {
75			t!("||") | t!("OR") => Some(BindingPower::Or),
76			t!("&&") | t!("AND") => Some(BindingPower::And),
77			t!("=") | t!("IS") | t!("==") | t!("!=") | t!("*=") | t!("?=") | t!("@") => {
78				Some(BindingPower::Equality)
79			}
80			t!("<") => {
81				if let Some(peek) = self.peek_whitespace1()
82					&& let t!("-") | t!("~") | t!("->") | t!("..") = peek.kind
83				{
84					return None;
85				}
86				Some(BindingPower::Relation)
87			}
88			t!(">") => {
89				if let Some(t!("..")) = self.peek_whitespace1().map(|x| x.kind) {
90					return Some(BindingPower::Range);
91				}
92				Some(BindingPower::Relation)
93			}
94			t!("..") => Some(BindingPower::Range),
95			t!("<=")
96			| t!(">=")
97			| t!("∋")
98			| t!("CONTAINS")
99			| t!("∌")
100			| t!("CONTAINSNOT")
101			| t!("∈")
102			| t!("INSIDE")
103			| t!("∉")
104			| t!("NOTINSIDE")
105			| t!("⊇")
106			| t!("CONTAINSALL")
107			| t!("⊃")
108			| t!("CONTAINSANY")
109			| t!("⊅")
110			| t!("CONTAINSNONE")
111			| t!("⊆")
112			| t!("ALLINSIDE")
113			| t!("⊂")
114			| t!("ANYINSIDE")
115			| t!("⊄")
116			| t!("NONEINSIDE")
117			| t!("OUTSIDE")
118			| t!("INTERSECTS")
119			| t!("NOT")
120			| t!("IN")
121			| t!("<|") => Some(BindingPower::Relation),
122			t!("+") | t!("-") => Some(BindingPower::AddSub),
123			t!("*") | t!("×") | t!("/") | t!("÷") | t!("%") => Some(BindingPower::MulDiv),
124			t!("**") => Some(BindingPower::Power),
125			t!("?:") | t!("?") => Some(BindingPower::Nullish),
126			_ => None,
127		}
128	}
129	fn prefix_binding_power(&mut self, token: TokenKind) -> Option<BindingPower> {
130		match token {
131			t!("!") | t!("+") | t!("-") => Some(BindingPower::Prefix),
132			t!("..") => Some(BindingPower::Range),
133			t!("<") => {
134				if let Some(peek) = self.peek_whitespace1() {
135					if peek.kind == t!("-") {
136						let recover = self.last_span();
137						if self.peek2().kind == TokenKind::Digits {
138							self.backup_after(recover);
139							return Some(BindingPower::Prefix);
140						}
141						return None;
142					}
143					if let t!("~") | t!("->") = peek.kind {
144						return None;
145					}
146				}
147				Some(BindingPower::Prefix)
148			}
149			_ => None,
150		}
151	}
152	fn postfix_binding_power(&mut self, token: TokenKind) -> Option<BindingPower> {
153		match token {
154			t!(">") => {
155				if let Some(peek) = self.peek_whitespace1()
156					&& let t!("..") = peek.kind
157				{
158					if let Some(peek) = self.peek_whitespace2()
159						&& (t!("=") == peek.kind || Self::kind_starts_expression(peek.kind))
160					{
161						return None;
162					} else {
163						return Some(BindingPower::Range);
164					}
165				}
166				None
167			}
168			t!("..") => match self.peek_whitespace1().map(|x| x.kind) {
169				Some(t!("=")) => None,
170				Some(x) if Self::kind_starts_expression(x) => None,
171				_ => Some(BindingPower::Range),
172			},
173			t!("(") => Some(BindingPower::Call),
174			_ => None,
175		}
176	}
177	async fn parse_prefix_op(&mut self, stk: &mut Stk, min_bp: BindingPower) -> ParseResult<Expr> {
178		let token = self.peek();
179		let operator = match token.kind {
180			t!("+") => {
181				if let Some(TokenKind::Digits) = self.peek_whitespace1().map(|x| x.kind) {
182					self.pop_peek();
183					let expr = match self.next_token_value::<Numeric>()? {
184						Numeric::Float(f) => Expr::Literal(Literal::Float(f)),
185						Numeric::Integer(i) => {
186							Expr::Literal(Literal::Integer(i.into_int(self.recent_span())?))
187						}
188						Numeric::Decimal(d) => Expr::Literal(Literal::Decimal(d)),
189						Numeric::Duration(d) => Expr::Prefix {
190							op: PrefixOperator::Positive,
191							expr: Box::new(Expr::Literal(Literal::Duration(PublicDuration::from(
192								d,
193							)))),
194						},
195					};
196					if self.peek_continues_idiom() {
197						return self
198							.parse_remaining_value_idiom(stk, vec![Part::Start(expr)])
199							.await;
200					} else {
201						return Ok(expr);
202					}
203				}
204				self.pop_peek();
205				PrefixOperator::Positive
206			}
207			t!("-") => {
208				if let Some(TokenKind::Digits) = self.peek_whitespace1().map(|x| x.kind) {
209					self.pop_peek();
210					let expr = match self.next_token_value::<Numeric>()? {
211						Numeric::Float(f) => Expr::Literal(Literal::Float(-f)),
212						Numeric::Integer(i) => {
213							Expr::Literal(Literal::Integer(i.into_neg_int(self.recent_span())?))
214						}
215						Numeric::Decimal(d) => Expr::Literal(Literal::Decimal(-d)),
216						Numeric::Duration(d) => Expr::Prefix {
217							op: PrefixOperator::Negate,
218							expr: Box::new(Expr::Literal(Literal::Duration(PublicDuration::from(
219								d,
220							)))),
221						},
222					};
223					if self.peek_continues_idiom() {
224						return self
225							.parse_remaining_value_idiom(stk, vec![Part::Start(expr)])
226							.await;
227					} else {
228						return Ok(expr);
229					}
230				}
231				self.pop_peek();
232				PrefixOperator::Negate
233			}
234			t!("!") => {
235				self.pop_peek();
236				PrefixOperator::Not
237			}
238			t!("<") => {
239				self.pop_peek();
240				let kind = self.parse_kind(stk, token.span).await?;
241				PrefixOperator::Cast(kind)
242			}
243			t!("..") => {
244				self.pop_peek();
245				if let Some(x) = self.peek_whitespace() {
246					if let t!("=") = x.kind {
247						self.pop_peek();
248						PrefixOperator::RangeInclusive
249					} else if !Self::kind_starts_prime_value(x.kind) {
250						return Ok(Expr::Literal(Literal::UnboundedRange));
251					} else {
252						PrefixOperator::Range
253					}
254				} else {
255					return Ok(Expr::Literal(Literal::UnboundedRange));
256				}
257			}
258			_ => unreachable!(),
259		};
260		let v = stk.run(|stk| self.pratt_parse_expr(stk, min_bp)).await?;
261		Ok(Expr::Prefix {
262			op: operator,
263			expr: Box::new(v),
264		})
265	}
266	pub(super) fn parse_nearest_neighbor(&mut self, token: Token) -> ParseResult<NearestNeighbor> {
267		let amount = self.next_token_value()?;
268		let res = if self.eat(t!(",")) {
269			let token = self.peek();
270			match token.kind {
271				TokenKind::Distance(_) => {
272					let d = self.parse_distance()?;
273					NearestNeighbor::K(amount, d)
274				}
275				TokenKind::Digits => {
276					let ef = self.next_token_value()?;
277					NearestNeighbor::Approximate(amount, ef)
278				}
279				_ => {
280					bail!(
281						"Unexpected token {} expected a distance of an integer", token
282						.kind, @ token.span =>
283						"The NN operator accepts either a distance or an EF value (integer)"
284					)
285				}
286			}
287		} else {
288			NearestNeighbor::KTree(amount)
289		};
290		if !self.eat(t!("|")) || !self.eat_whitespace(t!(">")) {
291			bail!(
292				"Unexpected token `{}` expected delimiter `|>`", self.peek().kind, @ self
293				.recent_span(), @ token.span => "expected this delimiter to close"
294			);
295		}
296		Ok(res)
297	}
298	/// Returns if an operator has a defined associativity.
299	/// For example: `a - b - c == (a - b) - c` so `-` is left associative.
300	/// However `a == b == c` is not defined to be either `(a == b) == c` nor `a == (b == c)`.
301	fn operator_has_associativity(operator: &BinaryOperator) -> bool {
302		!matches!(
303			operator,
304			BinaryOperator::Equal
305				| BinaryOperator::NotEqual
306				| BinaryOperator::AllEqual
307				| BinaryOperator::AnyEqual
308				| BinaryOperator::LessThan
309				| BinaryOperator::LessThanEqual
310				| BinaryOperator::MoreThan
311				| BinaryOperator::MoreThanEqual
312				| BinaryOperator::Matches(_)
313				| BinaryOperator::Contain
314				| BinaryOperator::NotContain
315				| BinaryOperator::ContainAll
316				| BinaryOperator::ContainAny
317				| BinaryOperator::ContainNone
318				| BinaryOperator::Inside
319				| BinaryOperator::NotInside
320				| BinaryOperator::AllInside
321				| BinaryOperator::AnyInside
322				| BinaryOperator::NoneInside
323				| BinaryOperator::Outside
324				| BinaryOperator::Intersects
325				| BinaryOperator::NearestNeighbor(_)
326		)
327	}
328	fn expr_is_range(expr: &Expr) -> bool {
329		match expr {
330			Expr::Binary { op, .. } => {
331				matches!(
332					op,
333					BinaryOperator::Range
334						| BinaryOperator::RangeSkipInclusive
335						| BinaryOperator::RangeSkip
336						| BinaryOperator::RangeInclusive
337				)
338			}
339			Expr::Prefix { op, .. } => {
340				matches!(op, PrefixOperator::Range | PrefixOperator::RangeInclusive)
341			}
342			Expr::Postfix { op, .. } => {
343				matches!(op, PostfixOperator::Range | PostfixOperator::RangeSkip)
344			}
345			_ => false,
346		}
347	}
348	async fn parse_infix_op(
349		&mut self,
350		stk: &mut Stk,
351		min_bp: BindingPower,
352		lhs: Expr,
353		lhs_prime: bool,
354	) -> ParseResult<Expr> {
355		let token = self.next();
356		let operator = match token.kind {
357			t!("||") | t!("OR") => BinaryOperator::Or,
358			t!("&&") | t!("AND") => BinaryOperator::And,
359			t!("?:") => BinaryOperator::TenaryCondition,
360			t!("?") => {
361				if !self.eat_whitespace(t!("?")) {
362					unexpected!(self, token, "`??`")
363				}
364				BinaryOperator::NullCoalescing
365			}
366			t!("==") => BinaryOperator::ExactEqual,
367			t!("!=") => BinaryOperator::NotEqual,
368			t!("*=") => BinaryOperator::AllEqual,
369			t!("?=") => BinaryOperator::AnyEqual,
370			t!("=") => BinaryOperator::Equal,
371			t!("@") => {
372				let op = self.parse_matches()?;
373				BinaryOperator::Matches(op)
374			}
375			t!("<=") => BinaryOperator::LessThanEqual,
376			t!("<") => BinaryOperator::LessThan,
377			t!(">=") => BinaryOperator::MoreThanEqual,
378			t!("**") => BinaryOperator::Power,
379			t!("+") => BinaryOperator::Add,
380			t!("-") => BinaryOperator::Subtract,
381			t!("*") | t!("×") => BinaryOperator::Multiply,
382			t!("/") | t!("÷") => BinaryOperator::Divide,
383			t!("%") => BinaryOperator::Remainder,
384			t!("∋") | t!("CONTAINS") => BinaryOperator::Contain,
385			t!("∌") | t!("CONTAINSNOT") => BinaryOperator::NotContain,
386			t!("∈") | t!("INSIDE") => BinaryOperator::Inside,
387			t!("∉") | t!("NOTINSIDE") => BinaryOperator::NotInside,
388			t!("⊇") | t!("CONTAINSALL") => BinaryOperator::ContainAll,
389			t!("⊃") | t!("CONTAINSANY") => BinaryOperator::ContainAny,
390			t!("⊅") | t!("CONTAINSNONE") => BinaryOperator::ContainNone,
391			t!("⊆") | t!("ALLINSIDE") => BinaryOperator::AllInside,
392			t!("⊂") | t!("ANYINSIDE") => BinaryOperator::AnyInside,
393			t!("⊄") | t!("NONEINSIDE") => BinaryOperator::NoneInside,
394			t!("IS") => {
395				if self.eat(t!("NOT")) {
396					BinaryOperator::NotEqual
397				} else {
398					BinaryOperator::Equal
399				}
400			}
401			t!("OUTSIDE") => BinaryOperator::Outside,
402			t!("INTERSECTS") => BinaryOperator::Intersects,
403			t!("NOT") => {
404				expected!(self, t!("IN"));
405				BinaryOperator::NotInside
406			}
407			t!("IN") => BinaryOperator::Inside,
408			t!("<|") => {
409				BinaryOperator::NearestNeighbor(Box::new(self.parse_nearest_neighbor(token)?))
410			}
411			t!(">") => {
412				if let Some(t!("..")) = self.peek_whitespace().map(|x| x.kind) {
413					self.pop_peek();
414					if let Some(t!("=")) = self.peek_whitespace().map(|x| x.kind) {
415						self.pop_peek();
416						BinaryOperator::RangeSkipInclusive
417					} else {
418						BinaryOperator::RangeSkip
419					}
420				} else {
421					BinaryOperator::MoreThan
422				}
423			}
424			t!("..") => {
425				if let Some(t!("=")) = self.peek_whitespace().map(|x| x.kind) {
426					self.pop_peek();
427					BinaryOperator::RangeInclusive
428				} else {
429					BinaryOperator::Range
430				}
431			}
432			x => unreachable!("found non-operator token {x:?}"),
433		};
434		let rhs_covered = self.peek().kind == t!("(");
435		let rhs = stk.run(|ctx| self.pratt_parse_expr(ctx, min_bp)).await?;
436		let has_associatitivity = Self::operator_has_associativity(&operator);
437		if !lhs_prime
438			&& !has_associatitivity
439			&& BindingPower::for_expr(&lhs) == BindingPower::for_binary_operator(&operator)
440		{
441			let span = token.span.covers(self.recent_span());
442			if matches!(
443				operator,
444				BinaryOperator::Range
445					| BinaryOperator::RangeSkipInclusive
446					| BinaryOperator::RangeSkip
447					| BinaryOperator::RangeInclusive
448			) {
449				bail!(
450					"Chained range operators has no specified associativity", @ span =>
451					"use parens, '()', to specify which operator must be evaluated first"
452				)
453			} else {
454				bail!(
455					"Chained relational operators have no defined associativity.", @ span
456					=>
457					"Use parens, '()', to specify which operator must be evaluated first"
458				)
459			}
460		}
461		if !rhs_covered
462			&& !has_associatitivity
463			&& BindingPower::for_expr(&rhs) == BindingPower::for_binary_operator(&operator)
464		{
465			let span = token.span.covers(self.recent_span());
466			if matches!(
467				operator,
468				BinaryOperator::Range
469					| BinaryOperator::RangeSkipInclusive
470					| BinaryOperator::RangeSkip
471					| BinaryOperator::RangeInclusive
472			) {
473				bail!(
474					"Chained range operators have no defined associativity.", @ span =>
475					"Use parens, '()', to specify which operator must be evaluated first"
476				)
477			} else {
478				bail!(
479					"Chained relational operators have no defined associativity.", @ span
480					=>
481					"Use parens, '()', to specify which operator must be evaluated first"
482				)
483			}
484		}
485		Ok(Expr::Binary {
486			left: Box::new(lhs),
487			op: operator,
488			right: Box::new(rhs),
489		})
490	}
491	fn parse_matches(&mut self) -> ParseResult<MatchesOperator> {
492		let peek = self.peek();
493		match peek.kind {
494			TokenKind::Digits => {
495				let number = self.next_token_value()?;
496				let op = if self.eat(t!(",")) {
497					let peek = self.next();
498					let op = match peek.kind {
499						t!("AND") => BooleanOperator::And,
500						t!("OR") => BooleanOperator::Or,
501						_ => unexpected!(self, peek, "either `AND` or `OR`"),
502					};
503					Some(op)
504				} else {
505					None
506				};
507				expected!(self, t!("@"));
508				Ok(MatchesOperator {
509					operator: op,
510					rf: Some(number),
511				})
512			}
513			t!("AND") => {
514				self.pop_peek();
515				expected!(self, t!("@"));
516				Ok(MatchesOperator {
517					operator: Some(BooleanOperator::And),
518					rf: None,
519				})
520			}
521			t!("OR") => {
522				self.pop_peek();
523				expected!(self, t!("@"));
524				Ok(MatchesOperator {
525					operator: Some(BooleanOperator::Or),
526					rf: None,
527				})
528			}
529			t!("@") => {
530				self.pop_peek();
531				Ok(MatchesOperator {
532					operator: None,
533					rf: None,
534				})
535			}
536			_ => unexpected!(self, peek, "a match reference, operator or `@`"),
537		}
538	}
539	async fn parse_postfix(
540		&mut self,
541		stk: &mut Stk,
542		lhs: Expr,
543		lhs_prime: bool,
544	) -> ParseResult<Expr> {
545		let token = self.next();
546		let op = match token.kind {
547			t!(">") => {
548				assert!(self.eat_whitespace(t!("..")));
549				if !lhs_prime && Self::expr_is_range(&lhs) {
550					bail!(
551						"Chaining range operators has no specified associativity", @
552						token.span =>
553						"use parens, '()', to specify which operator must be evaluated first"
554					)
555				}
556				PostfixOperator::RangeSkip
557			}
558			t!("..") => {
559				if !lhs_prime && Self::expr_is_range(&lhs) {
560					bail!(
561						"Chaining range operators has no specified associativity", @
562						token.span =>
563						"use parens, '()', to specify which operator must be evaluated first"
564					)
565				}
566				PostfixOperator::Range
567			}
568			t!("(") => {
569				let mut args = Vec::new();
570				loop {
571					if self.eat(t!(")")) {
572						break;
573					}
574					let arg = stk.run(|ctx| self.parse_expr_inherit(ctx)).await?;
575					args.push(arg);
576					if !self.eat(t!(",")) {
577						self.expect_closing_delimiter(t!(")"), token.span)?;
578						break;
579					}
580				}
581				PostfixOperator::Call(args)
582			}
583			t!(".") => {
584				let name = self.parse_ident()?;
585				expected!(self, t!("("));
586				let mut args = Vec::new();
587				loop {
588					if self.eat(t!(")")) {
589						break;
590					}
591					let arg = stk.run(|ctx| self.parse_expr_inherit(ctx)).await?;
592					args.push(arg);
593					if !self.eat(t!(",")) {
594						self.expect_closing_delimiter(t!(")"), token.span)?;
595						break;
596					}
597				}
598				PostfixOperator::MethodCall(name, args)
599			}
600			x => unreachable!("found non-operator token {x:?}"),
601		};
602		Ok(Expr::Postfix {
603			expr: Box::new(lhs),
604			op,
605		})
606	}
607	/// The pratt parsing loop.
608	/// Parses expression according to binding power.
609	async fn pratt_parse_expr(&mut self, stk: &mut Stk, min_bp: BindingPower) -> ParseResult<Expr> {
610		let peek = self.peek();
611		let (mut lhs, mut lhs_prime) = if let Some(bp) = self.prefix_binding_power(peek.kind) {
612			(self.parse_prefix_op(stk, bp).await?, false)
613		} else {
614			(self.parse_prime_expr(stk).await?, true)
615		};
616		loop {
617			let token = self.peek();
618			if let Some(bp) = self.postfix_binding_power(token.kind) {
619				if bp <= min_bp {
620					break;
621				}
622				lhs = self.parse_postfix(stk, lhs, lhs_prime).await?;
623				lhs_prime = false;
624				continue;
625			}
626			if let t!("+=") | t!("-=") | t!("+?=") = token.kind {
627				unexpected!(
628					self, token, "an operator", =>
629					"assignment operators are only allowed in SET and DUPLICATE KEY UPDATE clauses"
630				)
631			}
632			let Some(bp) = self.infix_binding_power(token.kind) else {
633				break;
634			};
635			if bp <= min_bp {
636				break;
637			}
638			lhs = self.parse_infix_op(stk, bp, lhs, lhs_prime).await?;
639			lhs_prime = false;
640		}
641		Ok(lhs)
642	}
643	pub fn reject_letless_let(expr: &Expr, span: Span) -> ParseResult<()> {
644		let Expr::Binary { left, op, .. } = expr else {
645			return Ok(());
646		};
647		let Expr::Param(p) = &**left else {
648			return Ok(());
649		};
650		let BinaryOperator::Equal = op else {
651			return Ok(());
652		};
653		bail!(
654			"Parameter declarations without `let` are deprecated.", @ span =>
655			"Replace with `let {} = ...` to keep the previous behavior.", p.to_sql()
656		)
657	}
658}