orql 0.1.0

A toy SQL parser for a subset of the Oracle dialect.
Documentation
use super::{MetaTracker, ParserInner, Result};
use crate::{
    ast::{ForUpdate, ForUpdateLockOptions, ForUpdateOfColumns, Node},
    parser::parse_comma_separated,
    scanner::{Keyword, Reserved, Token, TokenType},
};

impl<'s, M> ParserInner<'s, M>
where
    M: MetaTracker<'s>,
{
    pub(super) fn parse_for_update(&mut self) -> Result<Option<ForUpdate<'s, M::NodeId>>> {
        if let Some(Token {
            ttype: TokenType::Keyword(Keyword::FOR),
            loc,
        }) = self.peek_token()?
        {
            let for_token = {
                let loc = *loc;
                self.consume_token()?;
                Node((), self.meta_tracker.on_node_start(loc))
            };
            let update_token = expect_token!(|t = self.next_token()| "the UPDATE keyword" match {
                TokenType::Keyword(Keyword::UPDATE) => Node((), self.meta_tracker.on_node_start(t.loc)),
            });
            let of_columns = if let Some(Token {
                ttype: TokenType::Keyword(Keyword::OF),
                loc,
            }) = self.peek_token()?
            {
                let of_token = {
                    let loc = *loc;
                    self.consume_token()?;
                    Node((), self.meta_tracker.on_node_start(loc))
                };
                let columns = parse_comma_separated(self, |parser| parser.parse_identifier())?;
                Some(ForUpdateOfColumns { of_token, columns })
            } else {
                None
            };
            let lock_opts = if let Some(t) = self.peek_token()? {
                match t.ttype {
                    TokenType::Keyword(Keyword::NOWAIT) => {
                        let loc = t.loc;
                        self.consume_token()?;
                        let nowait_token = Node((), self.meta_tracker.on_node_start(loc));
                        Some(ForUpdateLockOptions::NoWait { nowait_token })
                    }
                    // XXX
                    TokenType::Identifier(_, Some(reserved)) => match reserved {
                        Reserved::WAIT => {
                            let wait_token = {
                                let loc = t.loc;
                                self.consume_token()?;
                                Node((), self.meta_tracker.on_node_start(loc))
                            };
                            let duration = self.parse_integer_node()?;
                            Some(ForUpdateLockOptions::Wait {
                                wait_token,
                                duration,
                            })
                        }
                        Reserved::SKIP => {
                            let skip_token = {
                                let loc = t.loc;
                                self.consume_token()?;
                                Node((), self.meta_tracker.on_node_start(loc))
                            };
                            let locked_token = expect_reserved!(|t = self.next_token()| "the LOCKED keyword" match {
                                Reserved::LOCKED => Node((), self.meta_tracker.on_node_start(t.loc)),
                            });
                            Some(ForUpdateLockOptions::Skip {
                                skip_token,
                                locked_token,
                            })
                        }
                        _ => None,
                    },
                    _ => None,
                }
            } else {
                None
            };
            Ok(Some(ForUpdate {
                for_token,
                update_token,
                of_columns,
                lock_opts,
            }))
        } else {
            Ok(None)
        }
    }

    fn parse_integer_node(&mut self) -> Result<Node<&'s str, M::NodeId>> {
        expect_token!(|t = self.next_token()| "an integer" match {
            TokenType::Integer(s) => Ok(Node(s, self.meta_tracker.on_node_start(t.loc))),
        })
    }
}