Skip to main content

surql_parser/upstream/syn/parser/
value.rs

1use super::{ParseResult, Parser};
2use crate::compat::types::{
3	PublicArray, PublicDuration, PublicFile, PublicGeometry, PublicNumber, PublicObject,
4	PublicRange, PublicRecordId, PublicRecordIdKey, PublicSet, PublicTable, PublicUuid,
5	PublicValue,
6};
7use crate::upstream::syn::error::bail;
8use crate::upstream::syn::lexer::Lexer;
9use crate::upstream::syn::lexer::compound::{self, Numeric};
10use crate::upstream::syn::parser::mac::{expected, expected_whitespace};
11use crate::upstream::syn::parser::unexpected;
12use crate::upstream::syn::token::{Span, TokenKind, t};
13use reblessive::Stk;
14use std::cmp::Ordering;
15use std::collections::BTreeMap;
16use std::ops::Bound;
17trait ValueParseFunc {
18	async fn parse(parser: &mut Parser<'_>, stk: &mut Stk) -> ParseResult<PublicValue>;
19}
20struct SurrealQL;
21struct Json;
22impl ValueParseFunc for SurrealQL {
23	async fn parse(parser: &mut Parser<'_>, stk: &mut Stk) -> ParseResult<PublicValue> {
24		parser.parse_value(stk).await
25	}
26}
27impl ValueParseFunc for Json {
28	async fn parse(parser: &mut Parser<'_>, stk: &mut Stk) -> ParseResult<PublicValue> {
29		parser.parse_json(stk).await
30	}
31}
32impl Parser<'_> {
33	/// Parse a complete value which cannot contain non-literal expressions.
34	pub async fn parse_value(&mut self, stk: &mut Stk) -> ParseResult<PublicValue> {
35		let token = self.peek();
36		let res = match token.kind {
37			t!("NONE") => {
38				self.pop_peek();
39				PublicValue::None
40			}
41			t!("NULL") => {
42				self.pop_peek();
43				PublicValue::Null
44			}
45			TokenKind::NaN => {
46				self.pop_peek();
47				PublicValue::Number(PublicNumber::Float(f64::NAN))
48			}
49			TokenKind::Infinity => {
50				self.pop_peek();
51				PublicValue::Number(PublicNumber::Float(f64::INFINITY))
52			}
53			t!("true") => {
54				self.pop_peek();
55				PublicValue::Bool(true)
56			}
57			t!("false") => {
58				self.pop_peek();
59				PublicValue::Bool(false)
60			}
61			t!("{") => {
62				let open = self.pop_peek().span;
63				if self.eat(t!("}")) {
64					return Ok(PublicValue::Object(PublicObject::new()));
65				}
66				if self.eat(t!(",")) {
67					self.expect_closing_delimiter(t!("}"), open)?;
68					return Ok(PublicValue::Set(PublicSet::new()));
69				}
70				if let t!("\"")
71				| t!("'")
72				| TokenKind::Identifier
73				| TokenKind::Digits
74				| TokenKind::Keyword(_)
75				| TokenKind::Language(_)
76				| TokenKind::Algorithm(_)
77				| TokenKind::Distance(_)
78				| TokenKind::VectorType(_) = self.peek().kind
79					&& let Some(x) = self
80						.speculate(stk, async |stk, this| {
81							let key = this.parse_object_key()?;
82							if !this.eat(t!(":")) {
83								return Ok(None);
84							}
85							let value = stk.run(|stk| this.parse_value(stk)).await?;
86							let mut res = BTreeMap::new();
87							res.insert(key, value);
88							if this.eat(t!(",")) {
89								this.parse_value_object::<SurrealQL>(stk, open, res)
90									.await
91									.map(Some)
92							} else {
93								this.expect_closing_delimiter(t!("}"), open)?;
94								Ok(Some(PublicObject::from(res)))
95							}
96						})
97						.await?
98				{
99					if let Some(x) = PublicGeometry::try_from_object(&x) {
100						return Ok(PublicValue::Geometry(x));
101					} else {
102						return Ok(PublicValue::Object(x));
103					}
104				}
105				let set = self.parse_value_set::<SurrealQL>(stk, token.span).await?;
106				PublicValue::Set(set)
107			}
108			t!("[") => {
109				self.pop_peek();
110				self.parse_value_array::<SurrealQL>(stk, token.span)
111					.await
112					.map(PublicValue::Array)?
113			}
114			t!("\"") | t!("'") => {
115				let strand = self.parse_string_lit()?;
116				if self.settings.legacy_strands {
117					self.reparse_json_legacy_strand(stk, strand).await
118				} else {
119					PublicValue::String(strand)
120				}
121			}
122			t!("d\"") | t!("d'") => PublicValue::Datetime(self.next_token_value()?),
123			t!("u\"") | t!("u'") => PublicValue::Uuid(self.next_token_value()?),
124			t!("b\"") | t!("b'") => PublicValue::Bytes(self.next_token_value()?),
125			t!("f\"") | t!("f'") => {
126				if !self.settings.files_enabled {
127					unexpected!(self, token, "the experimental files feature to be enabled");
128				}
129				let file = self.next_token_value::<PublicFile>()?;
130				PublicValue::File(file)
131			}
132			t!("/") => {
133				let regex = self.next_token_value()?;
134				PublicValue::Regex(regex)
135			}
136			t!("(") => {
137				let open = self.pop_peek().span;
138				let peek = self.peek();
139				match peek.kind {
140					t!("+") | t!("-") | TokenKind::Digits => {
141						let before = peek.span;
142						let number = self.next_token_value::<Numeric>()?;
143						let number_span = before.covers(self.last_span());
144						if self.peek().kind == t!(",") {
145							let x = match number {
146								Numeric::Duration(_) | Numeric::Decimal(_) => {
147									bail!(
148										"Unexpected token, expected a non-decimal, non-NaN, number",
149										@ number_span =>
150										"Coordinate numbers can't be NaN or a decimal"
151									);
152								}
153								Numeric::Float(x) if x.is_nan() => {
154									bail!(
155										"Unexpected token, expected a non-decimal, non-NaN, number",
156										@ number_span =>
157										"Coordinate numbers can't be NaN or a decimal"
158									);
159								}
160								Numeric::Float(x) => x,
161								Numeric::Integer(x) => x.into_int(number_span)? as f64,
162							};
163							self.pop_peek();
164							let y = self.next_token_value::<f64>()?;
165							self.expect_closing_delimiter(t!(")"), open)?;
166							PublicValue::Geometry(PublicGeometry::Point(geo::Point::new(x, y)))
167						} else {
168							self.expect_closing_delimiter(t!(")"), open)?;
169							match number {
170								Numeric::Float(x) => PublicValue::Number(PublicNumber::Float(x)),
171								Numeric::Integer(x) => {
172									PublicValue::Number(PublicNumber::Int(x.into_int(number_span)?))
173								}
174								Numeric::Decimal(x) => {
175									PublicValue::Number(PublicNumber::Decimal(x))
176								}
177								Numeric::Duration(duration) => {
178									PublicValue::Duration(PublicDuration::from(duration))
179								}
180							}
181						}
182					}
183					_ => {
184						let res = stk.run(|stk| self.parse_value(stk)).await?;
185						self.expect_closing_delimiter(t!(")"), open)?;
186						res
187					}
188				}
189			}
190			t!("..") => {
191				self.pop_peek();
192				match self.peek_whitespace().map(|x| x.kind) {
193					Some(t!("=")) => {
194						self.pop_peek();
195						let v = stk.run(|stk| self.parse_value(stk)).await?;
196						PublicValue::Range(Box::new(PublicRange {
197							start: Bound::Unbounded,
198							end: Bound::Included(v),
199						}))
200					}
201					Some(x) if Self::kind_starts_expression(x) => {
202						let v = stk.run(|stk| self.parse_value(stk)).await?;
203						PublicValue::Range(Box::new(PublicRange {
204							start: Bound::Unbounded,
205							end: Bound::Excluded(v),
206						}))
207					}
208					_ => PublicValue::Range(Box::new(PublicRange {
209						start: Bound::Unbounded,
210						end: Bound::Unbounded,
211					})),
212				}
213			}
214			t!("-") | t!("+") | TokenKind::Digits => {
215				self.pop_peek();
216				let compound = self.lex_compound(token, compound::numeric)?;
217				match compound.value {
218					Numeric::Duration(x) => PublicValue::Duration(PublicDuration::from(x)),
219					Numeric::Integer(x) => {
220						PublicValue::Number(PublicNumber::Int(x.into_int(compound.span)?))
221					}
222					Numeric::Float(x) => PublicValue::Number(PublicNumber::Float(x)),
223					Numeric::Decimal(x) => PublicValue::Number(PublicNumber::Decimal(x)),
224				}
225			}
226			_ => self
227				.parse_value_record_id_inner::<SurrealQL>(stk)
228				.await
229				.map(PublicValue::RecordId)?,
230		};
231		match self.peek_whitespace().map(|x| x.kind) {
232			Some(t!(">")) => {
233				self.pop_peek();
234				expected_whitespace!(self, t!(".."));
235				match self.peek_whitespace().map(|x| x.kind) {
236					Some(t!("=")) => {
237						self.pop_peek();
238						let v = stk.run(|stk| self.parse_value(stk)).await?;
239						Ok(PublicValue::Range(Box::new(PublicRange {
240							start: Bound::Excluded(res),
241							end: Bound::Included(v),
242						})))
243					}
244					Some(x) if Self::kind_starts_expression(x) => {
245						let v = stk.run(|stk| self.parse_value(stk)).await?;
246						Ok(PublicValue::Range(Box::new(PublicRange {
247							start: Bound::Excluded(res),
248							end: Bound::Excluded(v),
249						})))
250					}
251					_ => Ok(PublicValue::Range(Box::new(PublicRange {
252						start: Bound::Excluded(res),
253						end: Bound::Unbounded,
254					}))),
255				}
256			}
257			Some(t!("..")) => {
258				self.pop_peek();
259				match self.peek_whitespace().map(|x| x.kind) {
260					Some(t!("=")) => {
261						self.pop_peek();
262						let v = stk.run(|stk| self.parse_value(stk)).await?;
263						Ok(PublicValue::Range(Box::new(PublicRange {
264							start: Bound::Included(res),
265							end: Bound::Included(v),
266						})))
267					}
268					Some(x) if Self::kind_starts_expression(x) => {
269						let v = stk.run(|stk| self.parse_value(stk)).await?;
270						Ok(PublicValue::Range(Box::new(PublicRange {
271							start: Bound::Included(res),
272							end: Bound::Excluded(v),
273						})))
274					}
275					_ => Ok(PublicValue::Range(Box::new(PublicRange {
276						start: Bound::Included(res),
277						end: Bound::Unbounded,
278					}))),
279				}
280			}
281			_ => Ok(res),
282		}
283	}
284	pub async fn parse_json(&mut self, stk: &mut Stk) -> ParseResult<PublicValue> {
285		let token = self.peek();
286		match token.kind {
287			t!("NULL") => {
288				self.pop_peek();
289				Ok(PublicValue::Null)
290			}
291			t!("true") => {
292				self.pop_peek();
293				Ok(PublicValue::Bool(true))
294			}
295			t!("false") => {
296				self.pop_peek();
297				Ok(PublicValue::Bool(false))
298			}
299			t!("{") => {
300				self.pop_peek();
301				self.parse_value_object::<Json>(stk, token.span, BTreeMap::new())
302					.await
303					.map(PublicValue::Object)
304			}
305			t!("[") => {
306				self.pop_peek();
307				self.parse_value_array::<Json>(stk, token.span)
308					.await
309					.map(PublicValue::Array)
310			}
311			t!("\"") | t!("'") => {
312				let strand = self.parse_string_lit()?;
313				if self.settings.legacy_strands {
314					Ok(self.reparse_json_legacy_strand(stk, strand).await)
315				} else {
316					Ok(PublicValue::String(strand))
317				}
318			}
319			t!("-") | t!("+") | TokenKind::Digits => {
320				self.pop_peek();
321				let compound = self.lex_compound(token, compound::numeric)?;
322				match compound.value {
323					Numeric::Duration(x) => Ok(PublicValue::Duration(PublicDuration::from(x))),
324					Numeric::Integer(x) => Ok(PublicValue::Number(PublicNumber::Int(
325						x.into_int(compound.span)?,
326					))),
327					Numeric::Float(x) => Ok(PublicValue::Number(PublicNumber::Float(x))),
328					Numeric::Decimal(x) => Ok(PublicValue::Number(PublicNumber::Decimal(x))),
329				}
330			}
331			_ => {
332				match self
333					.parse_value_record_id_inner::<Json>(stk)
334					.await
335					.map(PublicValue::RecordId)
336				{
337					Ok(x) => Ok(x),
338					Err(err) => {
339						tracing::debug!("Error parsing record id: {err:?}");
340						self.parse_value_table().await.map(PublicValue::Table)
341					}
342				}
343			}
344		}
345	}
346	async fn reparse_json_legacy_strand(&mut self, stk: &mut Stk, strand: String) -> PublicValue {
347		if let Ok(x) = Parser::new(strand.as_bytes())
348			.parse_value_record_id(stk)
349			.await
350		{
351			return PublicValue::RecordId(x);
352		}
353		if let Ok(x) = Lexer::lex_datetime(&strand) {
354			return PublicValue::Datetime(x);
355		}
356		if let Ok(x) = Lexer::lex_uuid(&strand) {
357			return PublicValue::Uuid(x);
358		}
359		PublicValue::String(strand)
360	}
361	async fn parse_value_object<VP>(
362		&mut self,
363		stk: &mut Stk,
364		start: Span,
365		mut obj: BTreeMap<String, PublicValue>,
366	) -> ParseResult<PublicObject>
367	where
368		VP: ValueParseFunc,
369	{
370		loop {
371			if self.eat(t!("}")) {
372				return Ok(PublicObject::from(obj));
373			}
374			let key = self.parse_object_key()?;
375			expected!(self, t!(":"));
376			let value = stk.run(|ctx| VP::parse(self, ctx)).await?;
377			obj.insert(key, value);
378			if !self.eat(t!(",")) {
379				self.expect_closing_delimiter(t!("}"), start)?;
380				return Ok(PublicObject::from(obj));
381			}
382		}
383	}
384	async fn parse_value_set<VP>(&mut self, stk: &mut Stk, start: Span) -> ParseResult<PublicSet>
385	where
386		VP: ValueParseFunc,
387	{
388		let mut set = PublicSet::new();
389		loop {
390			if self.eat(t!("}")) {
391				return Ok(set);
392			}
393			let value = stk.run(|stk| VP::parse(self, stk)).await?;
394			set.insert(value);
395			if !self.eat(t!(",")) {
396				if set.len() <= 1 {
397					unexpected!(
398						self, self.peek(), "`,`", =>
399						"Sets with a single value must have at least a single comma"
400					);
401				}
402				self.expect_closing_delimiter(t!("}"), start)?;
403				return Ok(set);
404			}
405		}
406	}
407	async fn parse_value_array<VP>(
408		&mut self,
409		stk: &mut Stk,
410		start: Span,
411	) -> ParseResult<PublicArray>
412	where
413		VP: ValueParseFunc,
414	{
415		let mut array = Vec::new();
416		loop {
417			if self.eat(t!("]")) {
418				return Ok(PublicArray::from(array));
419			}
420			let value = stk.run(|stk| VP::parse(self, stk)).await?;
421			array.push(value);
422			if !self.eat(t!(",")) {
423				self.expect_closing_delimiter(t!("]"), start)?;
424				return Ok(PublicArray::from(array));
425			}
426		}
427	}
428	async fn parse_value_table(&mut self) -> ParseResult<PublicTable> {
429		let table = self.parse_ident()?;
430		Ok(PublicTable::new(table))
431	}
432	pub async fn parse_value_record_id(&mut self, stk: &mut Stk) -> ParseResult<PublicRecordId> {
433		self.parse_value_record_id_inner::<SurrealQL>(stk).await
434	}
435	async fn parse_value_record_id_inner<VP>(
436		&mut self,
437		stk: &mut Stk,
438	) -> ParseResult<PublicRecordId>
439	where
440		VP: ValueParseFunc,
441	{
442		let table = self.parse_ident()?;
443		expected!(self, t!(":"));
444		let peek = self.peek();
445		let key = match peek.kind {
446			t!("u'") | t!("u\"") => PublicRecordIdKey::Uuid(self.next_token_value::<PublicUuid>()?),
447			t!("{") => {
448				let peek = self.pop_peek();
449				PublicRecordIdKey::Object(
450					self.parse_value_object::<VP>(stk, peek.span, BTreeMap::new())
451						.await?,
452				)
453			}
454			t!("[") => {
455				let peek = self.pop_peek();
456				PublicRecordIdKey::Array(self.parse_value_array::<VP>(stk, peek.span).await?)
457			}
458			t!("+") => {
459				self.pop_peek();
460				let digits_token = if let Some(digits_token) = self.peek_whitespace() {
461					match digits_token.kind {
462						TokenKind::Digits => digits_token,
463						_ => unexpected!(self, digits_token, "an integer"),
464					}
465				} else {
466					bail!(
467						"Unexpected whitespace",@ self.last_span() =>
468						"No whitespace allowed after this token"
469					)
470				};
471				match self.peek_whitespace().map(|x| x.kind) {
472					Some(t!(".")) => {
473						unexpected!(
474							self, self.peek(), "an integer", =>
475							"Numeric Record-id keys can only be integers"
476						);
477					}
478					Some(x) if Self::kind_is_identifier(x) => {
479						let span = peek.span.covers(self.peek().span);
480						bail!("Unexpected token `{x}` expected an integer", @ span);
481					}
482					_ => {}
483				}
484				let digits_str = self.span_str(digits_token.span);
485				if let Ok(number) = digits_str.parse() {
486					PublicRecordIdKey::Number(number)
487				} else {
488					PublicRecordIdKey::String(digits_str.to_owned())
489				}
490			}
491			t!("-") => {
492				self.pop_peek();
493				let token = expected!(self, TokenKind::Digits);
494				if let Ok(number) = self.lex_compound(token, compound::integer::<u64>) {
495					match number.value.cmp(&((i64::MAX as u64) + 1)) {
496						Ordering::Less => PublicRecordIdKey::Number(-(number.value as i64)),
497						Ordering::Equal => PublicRecordIdKey::Number(i64::MIN),
498						Ordering::Greater => PublicRecordIdKey::String(format!(
499							"-{}",
500							self.lexer.span_str(number.span)
501						)),
502					}
503				} else {
504					PublicRecordIdKey::String(format!("-{}", self.lexer.span_str(token.span)))
505				}
506			}
507			TokenKind::Digits => {
508				if self.settings.flexible_record_id
509					&& let Some(peek) = self.peek_whitespace1()
510					&& Self::kind_is_identifier(peek.kind)
511				{
512					let ident = self.parse_flexible_ident()?;
513					PublicRecordIdKey::String(ident)
514				} else {
515					self.pop_peek();
516					let digits_str = self.span_str(peek.span);
517					if let Ok(number) = digits_str.parse::<i64>() {
518						PublicRecordIdKey::Number(number)
519					} else {
520						PublicRecordIdKey::String(digits_str.to_owned())
521					}
522				}
523			}
524			_ => {
525				let ident = if self.settings.flexible_record_id {
526					self.parse_flexible_ident()?
527				} else {
528					self.parse_ident()?
529				};
530				PublicRecordIdKey::String(ident)
531			}
532		};
533		Ok(PublicRecordId::new(table, key))
534	}
535}