@@ -45,6 +45,7 @@ pub enum ParsingError {
4545 InvalidSection ( Span ) ,
4646 MixedSectionContent ( Span ) ,
4747 MixedBracketContent ( Span ) ,
48+ MixedStepContent ( Span ) ,
4849 InvalidInvocation ( Span ) ,
4950 InvalidFunction ( Span ) ,
5051 InvalidTuple ( Span ) ,
@@ -83,6 +84,7 @@ impl ParsingError {
8384 | ParsingError :: InvalidSection ( span)
8485 | ParsingError :: MixedSectionContent ( span)
8586 | ParsingError :: MixedBracketContent ( span)
87+ | ParsingError :: MixedStepContent ( span)
8688 | ParsingError :: InvalidInvocation ( span)
8789 | ParsingError :: InvalidFunction ( span)
8890 | ParsingError :: InvalidTuple ( span)
@@ -1568,8 +1570,7 @@ impl<'i> Parser<'i> {
15681570 let span = self . span_since ( start) ;
15691571 Ok ( Expression :: String ( parts, span) )
15701572 } else if is_enum_response ( content) {
1571- let value =
1572- self . take_block_chars ( "a response literal" , '\'' , '\'' , |inner| Ok ( inner. source ) ) ?;
1573+ let value = self . read_enum_response ( ) ?;
15731574 let span = self . span_since ( start) ;
15741575 Ok ( Expression :: Response ( value, span) )
15751576 } else if is_invocation ( content) {
@@ -2613,19 +2614,48 @@ impl<'i> Parser<'i> {
26132614 )
26142615 }
26152616
2617+ /// Parse a single response literal like 'Yes'
2618+ fn read_enum_response ( & mut self ) -> Result < & ' i str , ParsingError > {
2619+ let start = self . offset ;
2620+ let value =
2621+ self . take_block_chars ( "a response literal" , '\'' , '\'' , |inner| Ok ( inner. source ) ) ?;
2622+
2623+ // There has to be a value, and it must not be padded as `'Yes'` and
2624+ // `' Yes '` would differ but render identically.
2625+ if value. is_empty ( ) || value != value. trim_ascii ( ) {
2626+ return Err ( ParsingError :: InvalidResponse ( Span :: new ( start, 0 ) ) ) ;
2627+ }
2628+
2629+ Ok ( value)
2630+ }
2631+
26162632 /// Parse enum responses like 'Yes' | 'No' | 'Not Applicable'
26172633 fn read_responses ( & mut self ) -> Result < Vec < Response < ' i > > , ParsingError > {
2618- self . take_split_by ( '|' , |inner| {
2619- let mut resp = validate_response ( inner. source )
2620- . ok_or ( ParsingError :: InvalidResponse ( Span :: new ( inner. offset , 0 ) ) ) ?;
2621- resp. span = Span :: new (
2622- inner. offset ,
2623- inner
2624- . source
2625- . len ( ) ,
2626- ) ;
2627- Ok ( resp)
2628- } )
2634+ // The block is the run of lines beginning with a response literal, so
2635+ // that whatever follows the enum is left for the enclosing scope.
2636+ self . take_block_lines (
2637+ is_enum_response,
2638+ |line| !is_enum_response ( line) ,
2639+ |outer| {
2640+ outer. take_split_by ( '|' , |inner| {
2641+ let span = Span :: new (
2642+ inner. offset ,
2643+ inner
2644+ . source
2645+ . len ( ) ,
2646+ ) ;
2647+ let value = inner. read_enum_response ( ) ?;
2648+
2649+ // a response is the literal and nothing else
2650+ inner. trim_whitespace ( ) ;
2651+ if !inner. is_finished ( ) {
2652+ return Err ( ParsingError :: InvalidResponse ( Span :: new ( span. offset , 0 ) ) ) ;
2653+ }
2654+
2655+ Ok ( Response { value, span } )
2656+ } )
2657+ } ,
2658+ )
26292659 }
26302660
26312661 fn parse_multiline_content ( & mut self ) -> Result < ( Option < & ' i str > , Vec < & ' i str > ) , ParsingError > {
@@ -2844,6 +2874,10 @@ impl<'i> Parser<'i> {
28442874 span : self . span_since ( responses_start) ,
28452875 } ) ;
28462876 } else {
2877+ // an enum answers the step it is in, so text cannot follow it
2878+ if let Some ( Scope :: ResponseBlock { .. } ) = scopes. last ( ) {
2879+ return Err ( ParsingError :: MixedStepContent ( Span :: new ( self . offset , 0 ) ) ) ;
2880+ }
28472881 break ;
28482882 }
28492883 }
0 commit comments