1use super::basic::NumberToken;
2use super::mac::{expected, unexpected};
3use super::{ParseResult, Parser};
4use crate::upstream::sql::field::Selector;
5use crate::upstream::sql::lookup::LookupKind;
6use crate::upstream::sql::part::{DestructurePart, Recurse, RecurseInstruction};
7use crate::upstream::sql::{Dir, Expr, Field, Fields, Idiom, Literal, Lookup, Param, Part};
8use crate::upstream::syn::error::bail;
9use crate::upstream::syn::lexer::compound::{self, Numeric};
10use crate::upstream::syn::token::{Span, TokenKind, t};
11use reblessive::Stk;
12impl Parser<'_> {
13 pub(super) fn peek_continues_idiom(&mut self) -> bool {
14 let peek = self.peek().kind;
15 if matches!(peek, t!("->") | t!("[") | t!(".") | t!("...")) {
16 return true;
17 }
18 peek == t!("<") && matches!(self.peek1().kind, t!("-") | t!("~") | t!("->"))
19 }
20 pub async fn parse_fields(&mut self, stk: &mut Stk) -> ParseResult<Fields> {
26 if self.eat(t!("VALUE")) {
27 let expr = stk.run(|ctx| self.parse_expr_field(ctx)).await?;
28 let alias = if self.eat(t!("AS")) {
29 Some(self.parse_basic_idiom()?)
30 } else {
31 None
32 };
33 Ok(Fields::Value(Box::new(Selector { expr, alias })))
34 } else {
35 let mut fields = Vec::new();
36 loop {
37 let field = if self.eat(t!("*")) {
38 Field::All
39 } else {
40 let expr = stk.run(|ctx| self.parse_expr_field(ctx)).await?;
41 let alias = if self.eat(t!("AS")) {
42 Some(self.parse_plain_idiom(stk).await?)
43 } else {
44 None
45 };
46 Field::Single(Selector { expr, alias })
47 };
48 fields.push(field);
49 if !self.eat(t!(",")) {
50 break;
51 }
52 }
53 Ok(Fields::Select(fields))
54 }
55 }
56 pub(super) async fn parse_idiom_list(&mut self, stk: &mut Stk) -> ParseResult<Vec<Idiom>> {
58 let mut res = vec![self.parse_plain_idiom(stk).await?];
59 while self.eat(t!(",")) {
60 res.push(self.parse_plain_idiom(stk).await?);
61 }
62 Ok(res)
63 }
64 pub(super) async fn parse_remaining_idiom(
71 &mut self,
72 stk: &mut Stk,
73 start: Vec<Part>,
74 ) -> ParseResult<Idiom> {
75 let mut res = start;
76 loop {
77 match self.peek_kind() {
78 t!("...") => {
79 self.pop_peek();
80 res.push(Part::Flatten);
81 }
82 t!(".") => {
83 self.pop_peek();
84 res.push(self.parse_dot_part(stk).await?)
85 }
86 t!("[") => {
87 let span = self.pop_peek().span;
88 let part = self.parse_bracket_part(stk, span).await?;
89 res.push(part)
90 }
91 t!("->") => {
92 self.pop_peek();
93 let lookup = stk
94 .run(|stk| self.parse_lookup(stk, LookupKind::Graph(Dir::Out)))
95 .await?;
96 res.push(Part::Graph(lookup))
97 }
98 t!("<") => {
99 if let Some(peek) = self.peek_whitespace1() {
100 if peek.kind == t!("~") {
101 self.pop_peek();
102 self.pop_peek();
103 let lookup = stk
104 .run(|stk| self.parse_lookup(stk, LookupKind::Reference))
105 .await?;
106 res.push(Part::Graph(lookup))
107 } else if peek.kind == t!("-") {
108 self.pop_peek();
109 self.pop_peek();
110 let lookup = stk
111 .run(|stk| self.parse_lookup(stk, LookupKind::Graph(Dir::In)))
112 .await?;
113 res.push(Part::Graph(lookup))
114 } else if peek.kind == t!("->") {
115 self.pop_peek();
116 self.pop_peek();
117 let lookup = stk
118 .run(|stk| self.parse_lookup(stk, LookupKind::Graph(Dir::Both)))
119 .await?;
120 res.push(Part::Graph(lookup))
121 } else {
122 break;
123 }
124 } else {
125 break;
126 }
127 }
128 _ => break,
129 }
130 }
131 Ok(Idiom(res))
132 }
133 pub(super) async fn parse_remaining_value_idiom(
142 &mut self,
143 stk: &mut Stk,
144 start: Vec<Part>,
145 ) -> ParseResult<Expr> {
146 let mut res = start;
147 loop {
148 match self.peek_kind() {
149 t!("...") => {
150 self.pop_peek();
151 res.push(Part::Flatten);
152 }
153 t!(".") => {
154 self.pop_peek();
155 res.push(self.parse_dot_part(stk).await?)
156 }
157 t!("[") => {
158 let span = self.pop_peek().span;
159 let part = self.parse_bracket_part(stk, span).await?;
160 res.push(part)
161 }
162 t!("->") => {
163 self.pop_peek();
164 let x = self.parse_lookup(stk, LookupKind::Graph(Dir::Out)).await?;
165 res.push(Part::Graph(x))
166 }
167 t!("<") => {
168 if let Some(peek) = self.peek_whitespace1() {
169 if peek.kind == t!("~") {
170 self.pop_peek();
171 self.pop_peek();
172 let lookup = self.parse_lookup(stk, LookupKind::Reference).await?;
173 res.push(Part::Graph(lookup))
174 } else if peek.kind == t!("-") {
175 self.pop_peek();
176 self.pop_peek();
177 let lookup = self.parse_lookup(stk, LookupKind::Graph(Dir::In)).await?;
178 res.push(Part::Graph(lookup))
179 } else if peek.kind == t!("->") {
180 self.pop_peek();
181 self.pop_peek();
182 let lookup =
183 self.parse_lookup(stk, LookupKind::Graph(Dir::Both)).await?;
184 res.push(Part::Graph(lookup))
185 } else {
186 break;
187 }
188 } else {
189 break;
190 }
191 }
192 _ => break,
193 }
194 }
195 Ok(Expr::Idiom(Idiom(res)))
196 }
197 pub async fn parse_plain_idiom(&mut self, stk: &mut Stk) -> ParseResult<Idiom> {
200 let start = match self.peek_kind() {
201 t!("->") => {
202 self.pop_peek();
203 let lookup = stk
204 .run(|ctx| self.parse_lookup(ctx, LookupKind::Graph(Dir::Out)))
205 .await?;
206 Part::Graph(lookup)
207 }
208 t!("<") => {
209 let t = self.pop_peek();
210 let lookup = if self.eat_whitespace(t!("~")) {
211 stk.run(|ctx| self.parse_lookup(ctx, LookupKind::Reference))
212 .await?
213 } else if self.eat_whitespace(t!("-")) {
214 stk.run(|ctx| self.parse_lookup(ctx, LookupKind::Graph(Dir::In)))
215 .await?
216 } else if self.eat_whitespace(t!("->")) {
217 stk.run(|ctx| self.parse_lookup(ctx, LookupKind::Graph(Dir::Both)))
218 .await?
219 } else {
220 unexpected!(self, t, "either `<-` `<->` or `->`")
221 };
222 Part::Graph(lookup)
223 }
224 _ => Part::Field(self.parse_ident()?),
225 };
226 let start = vec![start];
227 self.parse_remaining_idiom(stk, start).await
228 }
229 pub(super) async fn parse_dot_part(&mut self, stk: &mut Stk) -> ParseResult<Part> {
231 let res = match self.peek_kind() {
232 t!("?") => {
233 self.pop_peek();
234 Part::Optional
235 }
236 t!("*") => {
237 self.pop_peek();
238 Part::All
239 }
240 t!("@") => {
241 self.pop_peek();
242 Part::RepeatRecurse
243 }
244 t!("{") => {
245 self.pop_peek();
246 stk.run(|ctx| self.parse_curly_part(ctx)).await?
247 }
248 _ => {
249 let ident = self.parse_ident()?;
250 if self.eat(t!("(")) {
251 self.parse_function_part(stk, ident).await?
252 } else {
253 Part::Field(ident)
254 }
255 }
256 };
257 Ok(res)
258 }
259 pub(super) fn parse_basic_dot_part(&mut self) -> ParseResult<Part> {
261 let res = match self.peek_kind() {
262 t!("*") => {
263 self.pop_peek();
264 Part::All
265 }
266 _ => {
267 let ident = self.parse_ident()?;
268 Part::Field(ident)
269 }
270 };
271 Ok(res)
272 }
273 pub(super) async fn parse_function_part(
274 &mut self,
275 stk: &mut Stk,
276 name: String,
277 ) -> ParseResult<Part> {
278 let args = self.parse_function_args(stk).await?;
279 Ok(Part::Method(name, args))
280 }
281 pub(super) async fn parse_curly_part(&mut self, stk: &mut Stk) -> ParseResult<Part> {
283 match self.peek_kind() {
284 t!("*") | t!("..") | TokenKind::Digits => self.parse_recurse_part(stk).await,
285 _ => self.parse_destructure_part(stk).await,
286 }
287 }
288 pub(super) async fn parse_destructure_part(&mut self, stk: &mut Stk) -> ParseResult<Part> {
290 let start = self.last_span();
291 let mut destructured: Vec<DestructurePart> = Vec::new();
292 loop {
293 if self.eat(t!("}")) {
294 break;
295 }
296 let field = self.parse_ident()?;
297 let part = match self.peek_kind() {
298 t!(":") => {
299 self.pop_peek();
300 let idiom = match self.parse_expr_field(stk).await? {
301 Expr::Idiom(x) => x,
302 v => Idiom(vec![Part::Start(v)]),
303 };
304 DestructurePart::Aliased(field, idiom)
305 }
306 t!(".") => {
307 self.pop_peek();
308 let found = self.peek_kind();
309 match self.parse_dot_part(stk).await? {
310 Part::All => DestructurePart::All(field),
311 Part::Destructure(v) => DestructurePart::Destructure(field, v),
312 _ => {
313 bail!(
314 "Unexpected token `{}` expected a `*` or a destructuring",
315 found, @ self.last_span()
316 );
317 }
318 }
319 }
320 _ => DestructurePart::Field(field),
321 };
322 destructured.push(part);
323 if !self.eat(t!(",")) {
324 self.expect_closing_delimiter(t!("}"), start)?;
325 break;
326 }
327 }
328 Ok(Part::Destructure(destructured))
329 }
330 pub(super) fn parse_recurse_inner(&mut self) -> ParseResult<Recurse> {
333 let min = if matches!(self.peek().kind, TokenKind::Digits) {
334 Some(self.next_token_value::<u32>()?)
335 } else {
336 None
337 };
338 match (self.eat_whitespace(t!("..")), min) {
339 (true, _) => {}
340 (false, Some(v)) => {
341 return Ok(Recurse::Fixed(v));
342 }
343 _ => {
344 let found = self.next().kind;
345 bail!(
346 "Unexpected token `{}` expected an integer or ..", found, @ self
347 .last_span()
348 );
349 }
350 }
351 let max = if let Some(TokenKind::Digits) = self.peek_whitespace().map(|x| x.kind) {
352 Some(self.next_token_value::<u32>()?)
353 } else {
354 None
355 };
356 Ok(Recurse::Range(min, max))
357 }
358 pub(super) async fn parse_recurse_instruction(
360 &mut self,
361 stk: &mut Stk,
362 ) -> ParseResult<Option<RecurseInstruction>> {
363 let instruction = if self.eat(t!("+")) {
364 let kind = self.parse_ident()?;
365 if kind.eq_ignore_ascii_case("path") {
366 let mut inclusive = false;
367 loop {
368 if self.eat(t!("+")) {
369 let kind = self.parse_ident()?;
370 if kind.eq_ignore_ascii_case("inclusive") {
371 inclusive = true
372 } else {
373 bail!(
374 "Unexpected option `{}` expected `inclusive`", kind, @ self
375 .last_span()
376 );
377 }
378 } else {
379 break;
380 };
381 }
382 Some(RecurseInstruction::Path { inclusive })
383 } else if kind.eq_ignore_ascii_case("collect") {
384 let mut inclusive = false;
385 loop {
386 if self.eat(t!("+")) {
387 let kind = self.parse_ident()?;
388 if kind.eq_ignore_ascii_case("inclusive") {
389 inclusive = true
390 } else {
391 bail!(
392 "Unexpected option `{}` expected `inclusive`", kind, @ self
393 .last_span()
394 );
395 }
396 } else {
397 break;
398 };
399 }
400 Some(RecurseInstruction::Collect { inclusive })
401 } else if kind.eq_ignore_ascii_case("shortest") {
402 expected!(self, t!("="));
403 let token = self.peek();
404 let expects = match token.kind {
405 TokenKind::Parameter => Expr::Param(self.next_token_value::<Param>()?),
406 x if Parser::kind_is_identifier(x) => {
407 Expr::Literal(Literal::RecordId(self.parse_record_id(stk).await?))
408 }
409 _ => {
410 unexpected!(self, token, "a param or record-id");
411 }
412 };
413 let mut inclusive = false;
414 loop {
415 if self.eat(t!("+")) {
416 let kind = self.parse_ident()?;
417 if kind.eq_ignore_ascii_case("inclusive") {
418 inclusive = true
419 } else {
420 bail!(
421 "Unexpected option `{}` expected `inclusive`", kind, @ self
422 .last_span()
423 );
424 }
425 } else {
426 break;
427 };
428 }
429 Some(RecurseInstruction::Shortest { expects, inclusive })
430 } else {
431 bail!(
432 "Unexpected instruction `{}` expected `path`, `collect`, or `shortest`",
433 kind, @ self.last_span()
434 );
435 }
436 } else {
437 None
438 };
439 Ok(instruction)
440 }
441 pub(super) async fn parse_recurse_part(&mut self, stk: &mut Stk) -> ParseResult<Part> {
443 let start = self.last_span();
444 let recurse = self.parse_recurse_inner()?;
445 let instruction = self.parse_recurse_instruction(stk).await?;
446 self.expect_closing_delimiter(t!("}"), start)?;
447 let nest = if self.eat(t!("(")) {
448 let start = self.last_span();
449 let idiom = self.parse_remaining_idiom(stk, vec![]).await?;
450 self.expect_closing_delimiter(t!(")"), start)?;
451 Some(idiom)
452 } else {
453 None
454 };
455 Ok(Part::Recurse(recurse, nest, instruction))
456 }
457 pub(super) async fn parse_bracket_part(
459 &mut self,
460 stk: &mut Stk,
461 start: Span,
462 ) -> ParseResult<Part> {
463 let peek = self.peek();
464 let res = match peek.kind {
465 t!("*") => {
466 self.pop_peek();
467 Part::All
468 }
469 t!("$") => {
470 self.pop_peek();
471 Part::Last
472 }
473 t!("?") | t!("WHERE") => {
474 self.pop_peek();
475 let value = stk.run(|ctx| self.parse_expr_field(ctx)).await?;
476 Part::Where(value)
477 }
478 _ => {
479 let value = stk.run(|ctx| self.parse_expr_inherit(ctx)).await?;
480 Part::Value(value)
481 }
482 };
483 self.expect_closing_delimiter(t!("]"), start)?;
484 Ok(res)
485 }
486 pub(super) fn parse_basic_idiom(&mut self) -> ParseResult<Idiom> {
492 let start = self.parse_ident()?;
493 let mut parts = vec![Part::Field(start)];
494 loop {
495 let token = self.peek();
496 let part = match token.kind {
497 t!(".") => {
498 self.pop_peek();
499 self.parse_basic_dot_part()?
500 }
501 t!("[") => {
502 self.pop_peek();
503 let peek = self.peek();
504 let res = match peek.kind {
505 t!("*") => {
506 self.pop_peek();
507 Part::All
508 }
509 t!("$") => {
510 self.pop_peek();
511 Part::Last
512 }
513 TokenKind::Digits | t!("+") => {
514 let number = self.next_token_value::<NumberToken>()?;
515 let expr = match number {
516 NumberToken::Float(x) => Expr::Literal(Literal::Float(x)),
517 NumberToken::Integer(x) => {
518 Expr::Literal(Literal::Integer(x.into_int(self.recent_span())?))
519 }
520 NumberToken::Decimal(x) => Expr::Literal(Literal::Decimal(x)),
521 };
522 Part::Value(expr)
523 }
524 t!("-") => {
525 if let Some(peek_digit) = self.peek_whitespace1()
526 && let TokenKind::Digits = peek_digit.kind
527 {
528 let span = self.recent_span().covers(peek_digit.span);
529 bail!(
530 "Unexpected token `-` expected $, *, or a number", @ span =>
531 "an index in a basic idiom can't be negative"
532 );
533 }
534 unexpected!(self, peek, "$, * or a number");
535 }
536 _ => unexpected!(self, peek, "$, * or a number"),
537 };
538 self.expect_closing_delimiter(t!("]"), token.span)?;
539 res
540 }
541 _ => break,
542 };
543 parts.push(part);
544 }
545 Ok(Idiom(parts))
546 }
547 pub(super) fn parse_local_idiom(&mut self) -> ParseResult<Idiom> {
553 let start = self.parse_ident()?;
554 let mut parts = vec![Part::Field(start)];
555 loop {
556 let token = self.peek();
557 let part = match token.kind {
558 t!(".") => {
559 self.pop_peek();
560 self.parse_basic_dot_part()?
561 }
562 t!("[") => {
563 self.pop_peek();
564 let token = self.peek();
565 let res = match token.kind {
566 t!("*") => {
567 self.pop_peek();
568 Part::All
569 }
570 TokenKind::Digits | t!("+") => {
571 let next = self.next();
572 let number = self.lex_compound(next, compound::numeric)?;
573 let number = match number.value {
574 Numeric::Duration(_) => {
575 bail!(
576 "Unexpected token `duration` expected a number", @ number
577 .span
578 );
579 }
580 Numeric::Integer(x) => {
581 Expr::Literal(Literal::Integer(x.into_int(number.span)?))
582 }
583 Numeric::Float(x) => Expr::Literal(Literal::Float(x)),
584 Numeric::Decimal(x) => Expr::Literal(Literal::Decimal(x)),
585 };
586 Part::Value(number)
587 }
588 t!("-") => {
589 if let Some(peek_digit) = self.peek_whitespace1()
590 && let TokenKind::Digits = peek_digit.kind
591 {
592 let span = self.recent_span().covers(peek_digit.span);
593 bail!(
594 "Unexpected token `-` expected $, *, or a number", @ span =>
595 "index in a local idiom can't be negative"
596 );
597 }
598 unexpected!(self, token, "$, * or a number");
599 }
600 _ => unexpected!(self, token, "$, * or a number"),
601 };
602 self.expect_closing_delimiter(t!("]"), token.span)?;
603 res
604 }
605 _ => break,
606 };
607 parts.push(part);
608 }
609 if self.eat(t!("...")) {
610 let token = self.peek();
611 if let t!(".") | t!("[") = token.kind {
612 bail!(
613 "Unexpected token `...` expected a local idiom to end.", @ token.span
614 => "Flattening can only be done at the end of a local idiom"
615 )
616 }
617 parts.push(Part::Flatten);
618 }
619 Ok(Idiom(parts))
620 }
621 pub(super) async fn parse_what_list(&mut self, stk: &mut Stk) -> ParseResult<Vec<Expr>> {
626 let mut res = vec![stk.run(|ctx| self.parse_expr_table(ctx)).await?];
627 while self.eat(t!(",")) {
628 res.push(stk.run(|ctx| self.parse_expr_table(ctx)).await?)
629 }
630 Ok(res)
631 }
632 pub(super) async fn parse_lookup(
638 &mut self,
639 stk: &mut Stk,
640 lookup_kind: LookupKind,
641 ) -> ParseResult<Lookup> {
642 let token = self.peek();
643 match token.kind {
644 t!("?") => {
645 self.pop_peek();
646 Ok(Lookup {
647 kind: lookup_kind,
648 ..Default::default()
649 })
650 }
651 t!("(") => {
652 let span = self.pop_peek().span;
653 let expr = if self.eat(t!("SELECT")) {
654 let before = self.peek().span;
655 let expr = self.parse_fields(stk).await?;
656 let fields_span = before.covers(self.last_span());
657 expected!(self, t!("FROM"));
658 Some((expr, fields_span))
659 } else {
660 None
661 };
662 let token = self.peek();
663 let what = match token.kind {
664 t!("?") => {
665 self.pop_peek();
666 Vec::new()
667 }
668 x if Self::kind_is_identifier(x) => {
669 let subject = self.parse_lookup_subject(stk, true).await?;
670 let mut subjects = vec![subject];
671 while self.eat(t!(",")) {
672 subjects.push(self.parse_lookup_subject(stk, true).await?);
673 }
674 subjects
675 }
676 _ => unexpected!(self, token, "`?`, an identifier or a range"),
677 };
678 let cond = self.try_parse_condition(stk).await?;
679 let (split, group, order) = if let Some((ref expr, fields_span)) = expr {
680 let split_before = self.peek().span;
681 let split = self.try_parse_split(expr, fields_span)?;
682 let split_span = split
683 .as_ref()
684 .map(|_| split_before.covers(self.last_span()));
685 let group = self.try_parse_group(expr, fields_span, split_span)?;
686 let order = self.try_parse_orders(expr, fields_span)?;
687 (split, group, order)
688 } else {
689 (None, None, None)
690 };
691 let (limit, start) = if let t!("START") = self.peek_kind() {
692 let start = self.try_parse_start(stk).await?;
693 let limit = self.try_parse_limit(stk).await?;
694 (limit, start)
695 } else {
696 let limit = self.try_parse_limit(stk).await?;
697 let start = self.try_parse_start(stk).await?;
698 (limit, start)
699 };
700 let alias = if self.eat(t!("AS")) {
701 Some(self.parse_plain_idiom(stk).await?)
702 } else {
703 None
704 };
705 self.expect_closing_delimiter(t!(")"), span)?;
706 Ok(Lookup {
707 kind: lookup_kind,
708 what,
709 cond,
710 alias,
711 expr: expr.map(|(x, _)| x),
712 split,
713 group,
714 order,
715 limit,
716 start,
717 })
718 }
719 x if Self::kind_is_identifier(x) => {
720 let subject = self.parse_lookup_subject(stk, false).await?;
721 Ok(Lookup {
722 kind: lookup_kind,
723 what: vec![subject],
724 ..Default::default()
725 })
726 }
727 _ => unexpected!(self, token, "`?`, `(` or an identifier"),
728 }
729 }
730}