Newline,
CommentCommand,
DoRepeatCommand,
+ DoRepeatOverflow,
InlineData,
MacroId,
MacroName,
}
}
State::DoRepeat3 => PromptStyle::DoRepeat,
+ State::DoRepeat4 => PromptStyle::DoRepeat,
State::Define1 | State::Define2 | State::Define3 => {
if self.start_of_command() {
PromptStyle::First
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),
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),
DoRepeat1,
DoRepeat2,
DoRepeat3,
+ DoRepeat4,
Define1,
Define2,
Define3,
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);
}
}
}
}
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,
| Type::Punct
| Type::CommentCommand
| Type::DoRepeatCommand
+ | Type::DoRepeatOverflow
| Type::InlineData
| Type::MacroId
| Type::MacroName
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
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:
///
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;
}
}
);
}
+ #[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(