@@ -104,6 +104,8 @@ pub enum Token {
104104 UnicodeStringLiteral ( String ) ,
105105 /// Hexadecimal string literal: i.e.: X'deadbeef'
106106 HexStringLiteral ( String ) ,
107+ /// Interpolated text using Mustache-style syntax, e.g. {{FooBar}}.
108+ Mustache ( String ) ,
107109 /// Comma
108110 Comma ,
109111 /// Whitespace (space, tab, etc)
@@ -303,6 +305,7 @@ impl fmt::Display for Token {
303305 Token :: DoubleQuotedRawStringLiteral ( ref s) => write ! ( f, "R\" {s}\" " ) ,
304306 Token :: TripleSingleQuotedRawStringLiteral ( ref s) => write ! ( f, "R'''{s}'''" ) ,
305307 Token :: TripleDoubleQuotedRawStringLiteral ( ref s) => write ! ( f, "R\" \" \" {s}\" \" \" " ) ,
308+ Token :: Mustache ( ref s) => write ! ( f, "{{{s}}}" ) ,
306309 Token :: Comma => f. write_str ( "," ) ,
307310 Token :: Whitespace ( ws) => write ! ( f, "{ws}" ) ,
308311 Token :: DoubleEq => f. write_str ( "==" ) ,
@@ -1599,7 +1602,45 @@ impl<'a> Tokenizer<'a> {
15991602 _ => Ok ( Some ( Token :: Caret ) ) ,
16001603 }
16011604 }
1602- '{' => self . consume_and_return ( chars, Token :: LBrace ) ,
1605+ '{' => {
1606+ chars. next ( ) ; // consume the '{'
1607+ if let Some ( '{' ) = chars. peek ( ) {
1608+ chars. next ( ) ; // consume the second '{'
1609+
1610+ let mut s = String :: new ( ) ;
1611+ let mut is_terminated = false ;
1612+ let mut prev: Option < char > = None ;
1613+
1614+ while let Some ( & ch) = chars. peek ( ) {
1615+ if prev == Some ( '}' ) {
1616+ if ch == '}' {
1617+ chars. next ( ) ;
1618+ is_terminated = true ;
1619+ break ;
1620+ } else {
1621+ s. push ( '}' ) ;
1622+ s. push ( ch) ;
1623+ }
1624+ } else if ch != '}' {
1625+ s. push ( ch) ;
1626+ }
1627+
1628+ prev = Some ( ch) ;
1629+ chars. next ( ) ;
1630+ }
1631+
1632+ if chars. peek ( ) . is_none ( ) && !is_terminated {
1633+ self . tokenizer_error (
1634+ chars. location ( ) ,
1635+ "Unterminated mustache interpolation" ,
1636+ )
1637+ } else {
1638+ Ok ( Some ( Token :: Mustache ( s) ) )
1639+ }
1640+ } else {
1641+ Ok ( Some ( Token :: LBrace ) )
1642+ }
1643+ }
16031644 '}' => self . consume_and_return ( chars, Token :: RBrace ) ,
16041645 '#' if dialect_of ! ( self is SnowflakeDialect | BigQueryDialect | MySqlDialect | HiveDialect ) =>
16051646 {
0 commit comments