@@ -13,15 +13,33 @@ use std::ops::BitOr;
1313///
1414/// Can be used with the `Parser::reset` method to restore that state.
1515/// Should only be used with the `Parser` instance it came from.
16- #[ derive( Debug , Clone , Default ) ]
16+ #[ derive( Clone , Default ) ]
1717pub struct ParserState {
1818 pub ( crate ) position : usize ,
19- pub ( crate ) current_line_start_position : usize ,
20- pub ( crate ) current_line_number : u32 ,
21- pub ( crate ) at_start_of : Option < BlockType > ,
19+ pub ( crate ) current_line_start_position : u32 ,
20+ /// Current line number shifted by `Self::BLOCK_TYPE_BITS`, with the low 2 bits holding the
21+ /// `BlockType` discriminant of the block the last returned token opened (if any).
22+ line_number_and_block_type : u32 ,
23+ }
24+
25+ impl fmt:: Debug for ParserState {
26+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
27+ f. debug_struct ( "ParserState" )
28+ . field ( "position" , & self . position )
29+ . field (
30+ "current_line_start_position" ,
31+ & self . current_line_start_position ,
32+ )
33+ . field ( "current_line_number" , & self . line_number ( ) )
34+ . field ( "at_start_of" , & self . at_start_of ( ) )
35+ . finish ( )
36+ }
2237}
2338
2439impl ParserState {
40+ const BLOCK_TYPE_BITS : u32 = 2 ;
41+ const BLOCK_TYPE_MASK : u32 = ( 1 << Self :: BLOCK_TYPE_BITS ) - 1 ;
42+
2543 /// The position from the start of the input, counted in UTF-8 bytes.
2644 #[ inline]
2745 pub fn position ( & self ) -> SourcePosition {
@@ -32,10 +50,42 @@ impl ParserState {
3250 #[ inline]
3351 pub fn source_location ( & self ) -> SourceLocation {
3452 SourceLocation {
35- line : self . current_line_number ,
36- column : ( self . position - self . current_line_start_position + 1 ) as u32 ,
53+ line : self . line_number ( ) ,
54+ column : ( self . position as u32 )
55+ . wrapping_sub ( self . current_line_start_position )
56+ . wrapping_add ( 1 ) ,
3757 }
3858 }
59+
60+ #[ inline]
61+ pub ( crate ) fn line_number ( & self ) -> u32 {
62+ self . line_number_and_block_type >> Self :: BLOCK_TYPE_BITS
63+ }
64+
65+ #[ inline]
66+ pub ( crate ) fn advance_line_number ( & mut self , count : u32 ) {
67+ self . line_number_and_block_type += count << Self :: BLOCK_TYPE_BITS ;
68+ }
69+
70+ #[ inline]
71+ pub ( crate ) fn at_start_of ( & self ) -> Option < BlockType > {
72+ let block_type = ( self . line_number_and_block_type & Self :: BLOCK_TYPE_MASK ) as u8 ;
73+ BlockType :: from_byte ( block_type)
74+ }
75+
76+ #[ inline]
77+ pub ( crate ) fn set_at_start_of ( & mut self , block_type : BlockType ) {
78+ debug_assert ! ( self . at_start_of( ) . is_none( ) ) ;
79+ self . line_number_and_block_type |= block_type as u32 ;
80+ debug_assert_eq ! ( self . at_start_of( ) , Some ( block_type) ) ;
81+ }
82+
83+ #[ inline]
84+ pub ( crate ) fn take_at_start_of ( & mut self ) -> Option < BlockType > {
85+ let block_type = self . at_start_of ( ) ;
86+ self . line_number_and_block_type &= !Self :: BLOCK_TYPE_MASK ;
87+ block_type
88+ }
3989}
4090
4191/// When parsing until a given token, sometimes the caller knows that parsing is going to restart
@@ -241,20 +291,35 @@ struct CachedToken<'i> {
241291}
242292
243293#[ derive( Copy , Clone , PartialEq , Eq , Debug ) ]
294+ #[ repr( u8 ) ]
244295pub ( crate ) enum BlockType {
245- Parenthesis ,
296+ // NOTE: We rely on the discriminants being 1, 2, 3 for the `ParserState`
297+ // bit packing (and from_byte).
298+ Parenthesis = 1 ,
246299 SquareBracket ,
247300 CurlyBracket ,
248301}
249302
250303impl BlockType {
304+ #[ inline]
305+ fn from_byte ( b : u8 ) -> Option < BlockType > {
306+ let ty = match b {
307+ 1 => BlockType :: Parenthesis ,
308+ 2 => BlockType :: SquareBracket ,
309+ 3 => BlockType :: CurlyBracket ,
310+ _ => return None ,
311+ } ;
312+ debug_assert_eq ! ( ty as u8 , b) ;
313+ Some ( ty)
314+ }
315+
251316 fn closing ( token : & Token ) -> Option < BlockType > {
252- match * token {
253- Token :: CloseParenthesis => Some ( BlockType :: Parenthesis ) ,
254- Token :: CloseSquareBracket => Some ( BlockType :: SquareBracket ) ,
255- Token :: CloseCurlyBracket => Some ( BlockType :: CurlyBracket ) ,
256- _ => None ,
257- }
317+ Some ( match * token {
318+ Token :: CloseParenthesis => BlockType :: Parenthesis ,
319+ Token :: CloseSquareBracket => BlockType :: SquareBracket ,
320+ Token :: CloseCurlyBracket => BlockType :: CurlyBracket ,
321+ _ => return None ,
322+ } )
258323 }
259324}
260325
@@ -939,7 +1004,7 @@ pub fn parse_nested_block<'i, F, T, E>(
9391004where
9401005 F : FnOnce ( & mut Parser < ' i > ) -> Result < T , ParseError < E > > ,
9411006{
942- let block_type = parser. state . at_start_of . take ( ) . expect (
1007+ let block_type = parser. state . take_at_start_of ( ) . expect (
9431008 "\
9441009 A nested parser can only be created when a Function, \
9451010 ParenthesisBlock, SquareBracketBlock, or CurlyBracketBlock \
@@ -980,7 +1045,7 @@ impl Parser<'_> {
9801045 // FIXME: have a special-purpose tokenizer method for this that does less work.
9811046 while !self . is_eof ( ) {
9821047 let token = self . next_unchecked ( ) ;
983- if let Some ( nested_block_type) = self . state . at_start_of . take ( ) {
1048+ if let Some ( nested_block_type) = self . state . take_at_start_of ( ) {
9841049 stack. push ( nested_block_type) ;
9851050 continue ;
9861051 }
0 commit comments