1- use pgt_lexer:: { SyntaxKind , Token , TokenType } ;
1+ use pgt_lexer:: { SyntaxKind , Token , TokenType , WHITESPACE_TOKENS } ;
22
33use super :: {
44 Parser ,
@@ -24,6 +24,12 @@ pub fn source(p: &mut Parser) {
2424 } => {
2525 p. advance ( ) ;
2626 }
27+ Token {
28+ kind : SyntaxKind :: Ascii92 ,
29+ ..
30+ } => {
31+ plpgsql_command ( p) ;
32+ }
2733 _ => {
2834 statement ( p) ;
2935 }
@@ -87,6 +93,24 @@ pub(crate) fn parenthesis(p: &mut Parser) {
8793 }
8894}
8995
96+ pub ( crate ) fn plpgsql_command ( p : & mut Parser ) {
97+ p. expect ( SyntaxKind :: Ascii92 ) ;
98+
99+ loop {
100+ match p. current ( ) . kind {
101+ SyntaxKind :: Newline => {
102+ p. advance ( ) ;
103+ break ;
104+ }
105+ _ => {
106+ // advance the parser to the next token without ignoring irrelevant tokens
107+ // we would skip a newline with `advance()`
108+ p. current_pos += 1 ;
109+ }
110+ }
111+ }
112+ }
113+
90114pub ( crate ) fn case ( p : & mut Parser ) {
91115 p. expect ( SyntaxKind :: Case ) ;
92116
@@ -125,6 +149,36 @@ pub(crate) fn unknown(p: &mut Parser, exclude: &[SyntaxKind]) {
125149 } => {
126150 case ( p) ;
127151 }
152+ Token {
153+ kind : SyntaxKind :: Ascii92 ,
154+ ..
155+ } => {
156+ // pgsql commands e.g.
157+ //
158+ // ```
159+ // \if test
160+ // ```
161+ //
162+ // we wait for "\" and check if the previous token is a newline
163+
164+ // newline is a whitespace, but we do not want to ignore it here
165+ let irrelevant = WHITESPACE_TOKENS
166+ . iter ( )
167+ . filter ( |t| * * t != SyntaxKind :: Newline )
168+ . collect :: < Vec < _ > > ( ) ;
169+
170+ // go back from the current position without ignoring irrelevant tokens
171+ if p. tokens
172+ . iter ( )
173+ . take ( p. current_pos )
174+ . rev ( )
175+ . find ( |t| !irrelevant. contains ( & & t. kind ) )
176+ . is_some_and ( |t| t. kind == SyntaxKind :: Newline )
177+ {
178+ break ;
179+ }
180+ p. advance ( ) ;
181+ }
128182 Token {
129183 kind : SyntaxKind :: Ascii40 ,
130184 ..
0 commit comments