1use std::collections::BTreeMap;
2
3use reblessive::Stk;
4
5use crate::{
6 sql::{Block, Geometry, Object, Strand, Value},
7 syn::{
8 error::bail,
9 lexer::compound,
10 parser::{enter_object_recursion, mac::expected, ParseResult, Parser},
11 token::{t, Glued, Span, TokenKind},
12 },
13};
14
15use super::mac::unexpected;
16
17impl Parser<'_> {
18 pub(super) async fn parse_object_like(
22 &mut self,
23 ctx: &mut Stk,
24 start: Span,
25 ) -> ParseResult<Value> {
26 if self.eat(t!("}")) {
27 enter_object_recursion!(_this = self => {
29 return Ok(Value::Object(Object::default()));
30 })
31 }
32
33 if self.glue_and_peek1()?.kind == t!(":") {
35 enter_object_recursion!(this = self => {
36 return this.parse_object_or_geometry(ctx, start).await;
37 })
38 }
39
40 self.parse_block(ctx, start).await.map(Box::new).map(Value::Block)
42 }
43
44 async fn parse_object_or_geometry_after_type(
45 &mut self,
46 ctx: &mut Stk,
47 start: Span,
48 key: String,
49 ) -> ParseResult<Value> {
50 expected!(self, t!(":"));
51 let (t!("\"") | t!("'") | TokenKind::Glued(Glued::Strand)) = self.peek_kind() else {
53 return self
54 .parse_object_from_key(ctx, key, BTreeMap::new(), start)
55 .await
56 .map(Value::Object);
57 };
58
59 let type_value = self.next_token_value::<Strand>()?.0;
66 match type_value.as_str() {
67 "Point" => {
68 self.parse_geometry_after_type(
73 ctx,
74 start,
75 key,
76 type_value,
77 Geometry::array_to_point,
78 |x| Value::Geometry(Geometry::Point(x)),
79 )
80 .await
81 }
82 "LineString" => {
83 self.parse_geometry_after_type(
84 ctx,
85 start,
86 key,
87 type_value,
88 Geometry::array_to_line,
89 |x| Value::Geometry(Geometry::Line(x)),
90 )
91 .await
92 }
93 "Polygon" => {
94 self.parse_geometry_after_type(
95 ctx,
96 start,
97 key,
98 type_value,
99 Geometry::array_to_polygon,
100 |x| Value::Geometry(Geometry::Polygon(x)),
101 )
102 .await
103 }
104 "MultiPoint" => {
105 self.parse_geometry_after_type(
106 ctx,
107 start,
108 key,
109 type_value,
110 Geometry::array_to_multipoint,
111 |x| Value::Geometry(Geometry::MultiPoint(x)),
112 )
113 .await
114 }
115 "MultiLineString" => {
116 self.parse_geometry_after_type(
117 ctx,
118 start,
119 key,
120 type_value,
121 Geometry::array_to_multiline,
122 |x| Value::Geometry(Geometry::MultiLine(x)),
123 )
124 .await
125 }
126 "MultiPolygon" => {
127 self.parse_geometry_after_type(
128 ctx,
129 start,
130 key,
131 type_value,
132 Geometry::array_to_multipolygon,
133 |x| Value::Geometry(Geometry::MultiPolygon(x)),
134 )
135 .await
136 }
137 "GeometryCollection" => {
138 if !self.eat(t!(",")) {
139 return self
141 .parse_object_from_map(
142 ctx,
143 BTreeMap::from([(key, Value::Strand(type_value.into()))]),
144 start,
145 )
146 .await
147 .map(Value::Object);
148 }
149
150 let coord_key = self.parse_object_key()?;
151 if coord_key != "geometries" {
152 expected!(self, t!(":"));
153 return self
155 .parse_object_from_key(
156 ctx,
157 coord_key,
158 BTreeMap::from([(key, Value::Strand(type_value.into()))]),
159 start,
160 )
161 .await
162 .map(Value::Object);
163 }
164
165 expected!(self, t!(":"));
166
167 let value = ctx.run(|ctx| self.parse_value_inherit(ctx)).await?;
168
169 if !self.eat(t!(",")) {
171 self.expect_closing_delimiter(t!("}"), start)?;
172 } else {
173 if self.peek_kind() != t!("}") {
174 return self
176 .parse_object_from_map(
177 ctx,
178 BTreeMap::from([
179 (key, Value::Strand(type_value.into())),
180 (coord_key, value),
181 ]),
182 start,
183 )
184 .await
185 .map(Value::Object);
186 }
187 self.pop_peek();
188 }
189
190 if let Value::Array(x) = value {
192 if x.iter().all(|x| matches!(x, Value::Geometry(_))) {
194 let geometries =
195 x.0.into_iter()
196 .map(|x| {
197 if let Value::Geometry(x) = x {
198 x
199 } else {
200 unreachable!()
201 }
202 })
203 .collect();
204
205 return Ok(Value::Geometry(Geometry::Collection(geometries)));
206 }
207
208 return Ok(Value::Object(Object(BTreeMap::from([
209 (key, Value::Strand(type_value.into())),
210 (coord_key, Value::Array(x)),
211 ]))));
212 }
213
214 Ok(Value::Object(Object(BTreeMap::from([
216 (key, Value::Strand(type_value.into())),
217 (coord_key, value),
218 ]))))
219 }
220 _ => {
222 let object = BTreeMap::from([(key, Value::Strand(type_value.into()))]);
223
224 if self.eat(t!(",")) {
225 self.parse_object_from_map(ctx, object, start).await.map(Value::Object)
226 } else {
227 self.expect_closing_delimiter(t!("}"), start)?;
228 Ok(Value::Object(Object(object)))
229 }
230 }
231 }
232 }
233
234 async fn parse_object_or_geometry_after_coordinates(
235 &mut self,
236 ctx: &mut Stk,
237 start: Span,
238 key: String,
239 ) -> ParseResult<Value> {
240 expected!(self, t!(":"));
241
242 let value = ctx.run(|ctx| self.parse_value_inherit(ctx)).await?;
245
246 if !self.eat(t!(",")) {
247 self.expect_closing_delimiter(t!("}"), start)?;
249 return Ok(Value::Object(Object(BTreeMap::from([(key, value)]))));
250 }
251
252 if self.eat(t!("}")) {
253 return Ok(Value::Object(Object(BTreeMap::from([(key, value)]))));
255 }
256
257 let type_key = self.parse_object_key()?;
258 if type_key != "type" {
259 expected!(self, t!(":"));
260 return self
262 .parse_object_from_key(ctx, type_key, BTreeMap::from([(key, value)]), start)
263 .await
264 .map(Value::Object);
265 }
266 expected!(self, t!(":"));
267
268 let (t!("\"") | t!("'")) = self.peek_kind() else {
269 return self
271 .parse_object_from_key(ctx, type_key, BTreeMap::from([(key, value)]), start)
272 .await
273 .map(Value::Object);
274 };
275
276 let type_value = self.next_token_value::<Strand>()?.0;
277 let ate_comma = self.eat(t!(","));
278 match type_value.as_str() {
280 "Point" => {
281 if self.eat(t!("}")) {
282 if let Some(point) = Geometry::array_to_point(&value) {
283 return Ok(Value::Geometry(Geometry::Point(point)));
284 }
285 }
286 }
287 "LineString" => {
288 if self.eat(t!("}")) {
289 if let Some(point) = Geometry::array_to_line(&value) {
290 return Ok(Value::Geometry(Geometry::Line(point)));
291 }
292 }
293 }
294 "Polygon" => {
295 if self.eat(t!("}")) {
296 if let Some(point) = Geometry::array_to_polygon(&value) {
297 return Ok(Value::Geometry(Geometry::Polygon(point)));
298 }
299 }
300 }
301 "MultiPoint" => {
302 if self.eat(t!("}")) {
303 if let Some(point) = Geometry::array_to_multipolygon(&value) {
304 return Ok(Value::Geometry(Geometry::MultiPolygon(point)));
305 }
306 }
307 }
308 "MultiLineString" => {
309 if self.eat(t!("}")) {
310 if let Some(point) = Geometry::array_to_multiline(&value) {
311 return Ok(Value::Geometry(Geometry::MultiLine(point)));
312 }
313 }
314 }
315 "MultiPolygon" => {
316 if self.eat(t!("}")) {
317 if let Some(point) = Geometry::array_to_multipolygon(&value) {
318 return Ok(Value::Geometry(Geometry::MultiPolygon(point)));
319 }
320 }
321 }
322 _ => {}
323 };
324
325 if !ate_comma {
329 self.expect_closing_delimiter(t!("}"), start)?;
330 return Ok(Value::Object(Object(BTreeMap::from([
331 (key, value),
332 (type_key, Value::Strand(type_value.into())),
333 ]))));
334 }
335
336 self.parse_object_from_map(
337 ctx,
338 BTreeMap::from([(key, value), (type_key, Value::Strand(type_value.into()))]),
339 start,
340 )
341 .await
342 .map(Value::Object)
343 }
344
345 async fn parse_object_or_geometry_after_geometries(
346 &mut self,
347 ctx: &mut Stk,
348 start: Span,
349 key: String,
350 ) -> ParseResult<Value> {
351 expected!(self, t!(":"));
353
354 let value = ctx.run(|ctx| self.parse_value_inherit(ctx)).await?;
355
356 if !self.eat(t!(",")) || self.peek_kind() == t!("}") {
358 self.expect_closing_delimiter(t!("}"), start)?;
359 return Ok(Value::Object(Object(BTreeMap::from([(key, value)]))));
360 }
361
362 let type_key = self.parse_object_key()?;
364 if type_key != "type" {
366 expected!(self, t!(":"));
367 return self
368 .parse_object_from_key(ctx, type_key, BTreeMap::from([(key, value)]), start)
369 .await
370 .map(Value::Object);
371 }
372 expected!(self, t!(":"));
373 let (t!("\"") | t!("'")) = self.peek_kind() else {
375 return self
377 .parse_object_from_key(ctx, type_key, BTreeMap::from([(key, value)]), start)
378 .await
379 .map(Value::Object);
380 };
381
382 let type_value = self.next_token_value::<Strand>()?.0;
383 let ate_comma = self.eat(t!(","));
384
385 if type_value == "GeometryCollection" && self.eat(t!("}")) {
386 if let Value::Array(ref x) = value {
387 if x.iter().all(|x| matches!(x, Value::Geometry(_))) {
388 let Value::Array(x) = value else {
389 unreachable!()
390 };
391 let geometries = x
392 .into_iter()
393 .map(|x| {
394 if let Value::Geometry(x) = x {
395 x
396 } else {
397 unreachable!()
398 }
399 })
400 .collect();
401 return Ok(Value::Geometry(Geometry::Collection(geometries)));
402 }
403 }
404 }
405
406 if !ate_comma {
410 self.expect_closing_delimiter(t!("}"), start)?;
411 return Ok(Value::Object(Object(BTreeMap::from([
412 (key, value),
413 (type_key, Value::Strand(type_value.into())),
414 ]))));
415 }
416
417 self.parse_object_from_map(
418 ctx,
419 BTreeMap::from([(key, value), (type_key, Value::Strand(type_value.into()))]),
420 start,
421 )
422 .await
423 .map(Value::Object)
424 }
425
426 async fn parse_object_or_geometry(&mut self, ctx: &mut Stk, start: Span) -> ParseResult<Value> {
431 let key = self.parse_object_key()?;
433 match key.as_str() {
438 "type" => self.parse_object_or_geometry_after_type(ctx, start, key).await,
439 "coordinates" => self.parse_object_or_geometry_after_coordinates(ctx, start, key).await,
440 "geometries" => self.parse_object_or_geometry_after_geometries(ctx, start, key).await,
441 _ => {
442 expected!(self, t!(":"));
443 self.parse_object_from_key(ctx, key, BTreeMap::new(), start)
444 .await
445 .map(Value::Object)
446 }
447 }
448 }
449
450 async fn parse_geometry_after_type<F, Fm, R>(
451 &mut self,
452 ctx: &mut Stk,
453 start: Span,
454 key: String,
455 strand: String,
456 capture: F,
457 map: Fm,
458 ) -> ParseResult<Value>
459 where
460 F: FnOnce(&Value) -> Option<R>,
461 Fm: FnOnce(R) -> Value,
462 {
463 if !self.eat(t!(",")) {
464 self.expect_closing_delimiter(t!("}"), start)?;
466 return Ok(Value::Object(Object(BTreeMap::from([(
467 key,
468 Value::Strand(strand.into()),
469 )]))));
470 }
471 let coord_key = self.parse_object_key()?;
472 if coord_key != "coordinates" {
473 expected!(self, t!(":"));
474 return self
476 .parse_object_from_key(
477 ctx,
478 coord_key,
479 BTreeMap::from([(key, Value::Strand(strand.into()))]),
480 start,
481 )
482 .await
483 .map(Value::Object);
484 }
485 expected!(self, t!(":"));
486 let value = ctx.run(|ctx| self.parse_value_inherit(ctx)).await?;
487 let comma = self.eat(t!(","));
488 if !self.eat(t!("}")) {
489 if !comma {
491 bail!("Unexpected token, expected delimiter `}}`",
492 @self.recent_span(),
493 @start => "expected this delimiter to close"
494 );
495 }
496
497 return self
498 .parse_object_from_map(
499 ctx,
500 BTreeMap::from([(key, Value::Strand(strand.into())), (coord_key, value)]),
501 start,
502 )
503 .await
504 .map(Value::Object);
505 }
506
507 let Some(v) = capture(&value) else {
508 return Ok(Value::Object(Object(BTreeMap::from([
510 (key, Value::Strand(strand.into())),
511 (coord_key, value),
512 ]))));
513 };
514 Ok(map(v))
516 }
517
518 async fn parse_object_from_key(
519 &mut self,
520 ctx: &mut Stk,
521 key: String,
522 mut map: BTreeMap<String, Value>,
523 start: Span,
524 ) -> ParseResult<Object> {
525 let v = ctx.run(|ctx| self.parse_value_inherit(ctx)).await?;
526 map.insert(key, v);
527 if !self.eat(t!(",")) {
528 self.expect_closing_delimiter(t!("}"), start)?;
529 return Ok(Object(map));
530 }
531 self.parse_object_from_map(ctx, map, start).await
532 }
533
534 pub(super) async fn parse_object(&mut self, ctx: &mut Stk, start: Span) -> ParseResult<Object> {
541 enter_object_recursion!(this = self => {
542 this.parse_object_from_map(ctx, BTreeMap::new(), start).await
543 })
544 }
545
546 async fn parse_object_from_map(
547 &mut self,
548 ctx: &mut Stk,
549 mut map: BTreeMap<String, Value>,
550 start: Span,
551 ) -> ParseResult<Object> {
552 loop {
553 if self.eat(t!("}")) {
554 return Ok(Object(map));
555 }
556
557 let (key, value) = self.parse_object_entry(ctx).await?;
558 map.insert(key, value);
560
561 if !self.eat(t!(",")) {
562 self.expect_closing_delimiter(t!("}"), start)?;
563 return Ok(Object(map));
564 }
565 }
566 }
567
568 pub async fn parse_block(&mut self, ctx: &mut Stk, start: Span) -> ParseResult<Block> {
574 let mut statements = Vec::new();
575 loop {
576 while self.eat(t!(";")) {}
577 if self.eat(t!("}")) {
578 break;
579 }
580
581 let stmt = ctx.run(|ctx| self.parse_entry(ctx)).await?;
582 statements.push(stmt);
583 if !self.eat(t!(";")) {
584 self.expect_closing_delimiter(t!("}"), start)?;
585 break;
586 }
587 }
588 Ok(Block(statements))
589 }
590
591 async fn parse_object_entry(&mut self, ctx: &mut Stk) -> ParseResult<(String, Value)> {
594 let text = self.parse_object_key()?;
595 expected!(self, t!(":"));
596 let value = ctx.run(|ctx| self.parse_value_inherit(ctx)).await?;
597 Ok((text, value))
598 }
599
600 pub(super) fn parse_object_key(&mut self) -> ParseResult<String> {
602 let token = self.peek();
603 match token.kind {
604 x if Self::kind_is_keyword_like(x) => {
605 self.pop_peek();
606 let str = self.lexer.span_str(token.span);
607 Ok(str.to_string())
608 }
609 TokenKind::Identifier => {
610 self.pop_peek();
611 let str = self.lexer.string.take().unwrap();
612 Ok(str)
613 }
614 t!("\"") | t!("'") | TokenKind::Glued(Glued::Strand) => {
615 let str = self.next_token_value::<Strand>()?.0;
616 Ok(str)
617 }
618 TokenKind::Digits => {
619 self.pop_peek();
620 let span = self.lexer.lex_compound(token, compound::number)?.span;
621 let str = self.lexer.span_str(span);
622 Ok(str.to_string())
623 }
624 TokenKind::Glued(Glued::Number) => {
625 self.pop_peek();
626 let str = self.lexer.span_str(token.span);
627 Ok(str.to_string())
628 }
629 _ => unexpected!(self, token, "an object key"),
630 }
631 }
632}
633
634#[cfg(test)]
635mod test {
636 use super::*;
637 use crate::syn::Parse;
638
639 #[test]
640 fn block_value() {
641 let sql = "{ 80 }";
642 let out = Value::parse(sql);
643 assert_eq!(sql, out.to_string())
644 }
645
646 #[test]
647 fn block_ifelse() {
648 let sql = "{ RETURN IF true THEN 50 ELSE 40 END; }";
649 let out = Value::parse(sql);
650 assert_eq!(sql, out.to_string())
651 }
652
653 #[test]
654 fn block_multiple() {
655 let sql = r#"{
656
657 LET $person = (SELECT * FROM person WHERE first = $first AND last = $last AND birthday = $birthday);
658
659 RETURN IF $person[0].id THEN
660 $person[0]
661 ELSE
662 (CREATE person SET first = $first, last = $last, birthday = $birthday)
663 END;
664
665}"#;
666 let out = Value::parse(sql);
667 assert_eq!(sql, format!("{:#}", out))
668 }
669}
670
671#[cfg(test)]
672mod tests {
673 use super::*;
674 use crate::syn::Parse;
675
676 #[test]
677 fn simple() {
678 let sql = "(-0.118092, 51.509865)";
679 let out = Value::parse(sql);
680 assert!(matches!(out, Value::Geometry(_)));
681 assert_eq!("(-0.118092, 51.509865)", format!("{}", out));
682 }
683
684 #[test]
685 fn point() {
686 let sql = r#"{
687 type: 'Point',
688 coordinates: [-0.118092, 51.509865]
689 }"#;
690 let out = Value::parse(sql);
691 assert!(matches!(out, Value::Geometry(_)));
692 assert_eq!("(-0.118092, 51.509865)", format!("{}", out));
693 }
694
695 #[test]
696 fn polygon_exterior() {
697 let sql = r#"{
698 type: 'Polygon',
699 coordinates: [
700 [
701 [-0.38314819, 51.37692386], [0.1785278, 51.37692386],
702 [0.1785278, 51.61460570], [-0.38314819, 51.61460570],
703 [-0.38314819, 51.37692386]
704 ]
705 ]
706 }"#;
707 let out = Value::parse(sql);
708 assert!(matches!(out, Value::Geometry(_)));
709 assert_eq!("{ type: 'Polygon', coordinates: [[[-0.38314819, 51.37692386], [0.1785278, 51.37692386], [0.1785278, 51.6146057], [-0.38314819, 51.6146057], [-0.38314819, 51.37692386]]] }", format!("{}", out));
710 }
711
712 #[test]
713 fn polygon_interior() {
714 let sql = r#"{
715 type: 'Polygon',
716 coordinates: [
717 [
718 [-0.38314819, 51.37692386], [0.1785278, 51.37692386],
719 [0.1785278, 51.61460570], [-0.38314819, 51.61460570],
720 [-0.38314819, 51.37692386]
721 ],
722 [
723 [-0.38314819, 51.37692386], [0.1785278, 51.37692386],
724 [0.1785278, 51.61460570], [-0.38314819, 51.61460570],
725 [-0.38314819, 51.37692386]
726 ]
727 ]
728 }"#;
729 let out = Value::parse(sql);
730 assert!(matches!(out, Value::Geometry(_)));
731 assert_eq!("{ type: 'Polygon', coordinates: [[[-0.38314819, 51.37692386], [0.1785278, 51.37692386], [0.1785278, 51.6146057], [-0.38314819, 51.6146057], [-0.38314819, 51.37692386]], [[-0.38314819, 51.37692386], [0.1785278, 51.37692386], [0.1785278, 51.6146057], [-0.38314819, 51.6146057], [-0.38314819, 51.37692386]]] }", format!("{}", out));
732 }
733}