testing
authorBen Pfaff <blp@cs.stanford.edu>
Mon, 8 Jul 2024 15:57:05 +0000 (08:57 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Mon, 8 Jul 2024 15:57:05 +0000 (08:57 -0700)
rust/src/lex/segment.rs
rust/src/prompt.rs

index de75bde5682ba5be954a9b260f69f0ef45be55aa..94ead036b764a75a751b68486352438c91e07412 100644 (file)
@@ -71,6 +71,7 @@ pub enum Type {
     Newline,
     CommentCommand,
     DoRepeatCommand,
+    DoRepeatOverflow,
     InlineData,
     MacroId,
     MacroName,
@@ -168,6 +169,7 @@ impl Segmenter {
                 }
             }
             State::DoRepeat3 => PromptStyle::DoRepeat,
+            State::DoRepeat4 => PromptStyle::DoRepeat,
             State::Define1 | State::Define2 | State::Define3 => {
                 if self.start_of_command() {
                     PromptStyle::First
@@ -227,7 +229,7 @@ impl Segmenter {
                 if self.start_of_line() {
                     self.parse_start_of_line(input, eof)
                 } else {
-                    self.parse_mid_command(input, eof)
+                    self.parse_mid_line(input, eof)
                 }
             }
             State::Comment1 => self.parse_comment_1(input, eof),
@@ -241,6 +243,7 @@ impl Segmenter {
             State::DoRepeat1 => self.parse_do_repeat_1(input, eof),
             State::DoRepeat2 => self.parse_do_repeat_2(input, eof),
             State::DoRepeat3 => self.parse_do_repeat_3(input, eof),
+            State::DoRepeat4 => self.parse_do_repeat_4(input),
             State::Define1 => self.parse_define_1_2(input, eof),
             State::Define2 => self.parse_define_1_2(input, eof),
             State::Define3 => self.parse_define_3(input, eof),
@@ -270,6 +273,7 @@ enum State {
     DoRepeat1,
     DoRepeat2,
     DoRepeat3,
+    DoRepeat4,
     Define1,
     Define2,
     Define3,
@@ -425,6 +429,7 @@ fn detect_command_name(input: &str, eof: bool) -> Result<bool, Incomplete> {
     for command in get_command_name_candidates(command_name) {
         if let Some(m) = command_match(command, string) {
             if m.missing_words <= 0 {
+                println!("{command}");
                 return Ok(true);
             }
         }
@@ -495,9 +500,9 @@ impl Segmenter {
             }
         }
         self.state.1 = Substate::START_OF_COMMAND;
-        self.parse_mid_command(input, eof)
+        self.parse_mid_line(input, eof)
     }
-    fn parse_mid_command<'a>(
+    fn parse_mid_line<'a>(
         &mut self,
         input: &'a str,
         eof: bool,
@@ -650,6 +655,7 @@ impl Segmenter {
                 | Type::Punct
                 | Type::CommentCommand
                 | Type::DoRepeatCommand
+                | Type::DoRepeatOverflow
                 | Type::InlineData
                 | Type::MacroId
                 | Type::MacroName
@@ -1026,26 +1032,17 @@ impl Segmenter {
             input = take(input, eof).unwrap().1;
         }
     }
-    fn check_repeat_command<'a>(&mut self, input: &'a str, eof: bool) -> Result<(), Incomplete> {
+    fn check_repeat_command<'a>(&mut self, input: &'a str, eof: bool) -> Result<isize, Incomplete> {
         let input = input.strip_prefix(&['-', '+']).unwrap_or(input);
         let (id1, input) = self.next_id_in_command(input, eof)?;
-        let up = if id_match("DO", id1) {
-            true
-        } else if id_match("END", id1) {
-            false
+        if id_match("DO", id1) && id_match("REPEAT", self.next_id_in_command(input, eof)?.0) {
+            Ok(1)
+        } else if id_match("END", id1) && id_match("REPEAT", self.next_id_in_command(input, eof)?.0)
+        {
+            Ok(-1)
         } else {
-            return Ok(());
-        };
-
-        let (id2, _) = self.next_id_in_command(input, eof)?;
-        if id_match("REPEAT", id2) {
-            if up {
-                self.nest += 1
-            } else {
-                self.nest -= 1
-            };
+            Ok(0)
         }
-        Ok(())
     }
     /// We are in the body of `DO REPEAT`, segmenting the lines of syntax that
     /// are to be repeated.  Report each line of syntax as a single
@@ -1063,18 +1060,33 @@ impl Segmenter {
             return Ok((rest, Type::Newline));
         }
         let rest = self.parse_full_line(input, eof)?;
-        self.check_repeat_command(input, eof)?;
-        if self.nest == 0 {
-            // Nesting level dropped to 0, so we've finished reading the `DO
-            // REPEAT` body.
-            self.state = (
-                State::General,
-                Substate::START_OF_COMMAND | Substate::START_OF_LINE,
-            );
-            self.push(input, eof)
-        } else {
-            Ok((rest, Type::DoRepeatCommand))
+        let direction = self.check_repeat_command(input, eof)?;
+        if direction > 0 {
+            if let Some(nest) = self.nest.checked_add(1) {
+                self.nest = nest;
+            } else {
+                self.state.0 = State::DoRepeat4;
+            }
+        } else if direction < 0 {
+            self.nest -= 1;
+            if self.nest == 0 {
+                // Nesting level dropped to 0, so we've finished reading the `DO
+                // REPEAT` body.
+                self.state = (
+                    State::General,
+                    Substate::START_OF_COMMAND | Substate::START_OF_LINE,
+                );
+                return self.push(input, eof)
+            }
         }
+        return Ok((rest, Type::DoRepeatCommand))
+    }
+    fn parse_do_repeat_4<'a>(
+        &mut self,
+        input: &'a str,
+    ) -> Result<(&'a str, Type), Incomplete> {
+        self.state.0 = State::DoRepeat3;
+        Ok((input, Type::DoRepeatOverflow))
     }
     /// We are segmenting a `DEFINE` command, which consists of:
     ///
@@ -1326,10 +1338,13 @@ mod test {
             let (rest, type_) = segmenter.push(input, true).unwrap();
             let len = input.len() - rest.len();
             let token = &input[..len];
-            println!("{type_:?} {token:?}");
-            if type_ == Type::End {
-                break;
+            print!("{type_:?} {token:?}");
+            match type_ {
+                Type::Newline => print!(" ({:?})", segmenter.prompt()),
+                Type::End => break,
+                _ => (),
             }
+            println!();
             input = rest;
         }
     }
@@ -1560,6 +1575,19 @@ end repeat.
         );
     }
 
+    #[test]
+    fn test_do_repeat_overflow() {
+        let mut s = String::new();
+        const N: usize = 257;
+        for i in 0..N {
+            s.push_str(&format!("do repeat v{i}={i} thru {}\n", i + 5));
+        }
+        for i in (0..N).rev() {
+            s.push_str(&format!("end repeat. /* {i}\n"));
+        }
+        print_segmentation(&s);
+    }
+
     #[test]
     fn test_define_simple() {
         print_segmentation(
index 71a6b7ce2a0e5f206f14fad041d8429abac858c4..c02ca9b3672a8d80464b209b3ad0d52ed0ddd510 100644 (file)
@@ -1,3 +1,4 @@
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
 pub enum PromptStyle {
     /// First line of command.
     First,