From c11b681d56d477f2e037c3624428fb153617bb63 Mon Sep 17 00:00:00 2001 From: "NGnius (Graham)" Date: Tue, 4 Jan 2022 13:00:05 -0500 Subject: [PATCH] Fix some implementation bugs found while testing REPL --- mps-interpreter/src/lang/function.rs | 1 + mps-interpreter/src/lang/vocabulary/repeat.rs | 12 +++++++++-- .../src/lang/vocabulary/sql_query.rs | 5 ++++- .../src/lang/vocabulary/sql_simple_query.rs | 5 ++++- mps-interpreter/src/tokens/tokenizer.rs | 18 ++++++++++++----- src/main.rs | 2 +- src/repl.rs | 20 +++++++++++++++---- 7 files changed, 49 insertions(+), 14 deletions(-) diff --git a/mps-interpreter/src/lang/function.rs b/mps-interpreter/src/lang/function.rs index 6ba6548..9326ede 100644 --- a/mps-interpreter/src/lang/function.rs +++ b/mps-interpreter/src/lang/function.rs @@ -68,6 +68,7 @@ impl + 'static> BoxedMpsOpFactory assert_token_raw(MpsToken::OpenBracket, tokens)?; assert_token_raw_back(MpsToken::CloseBracket, tokens)?; let func = self.op_factory.build_function_params(name, tokens, dict)?; + #[cfg(debug_assertions)] assert_empty(tokens)?; Ok(Box::new(func)) } diff --git a/mps-interpreter/src/lang/vocabulary/repeat.rs b/mps-interpreter/src/lang/vocabulary/repeat.rs index c9cb4a4..6a88e34 100644 --- a/mps-interpreter/src/lang/vocabulary/repeat.rs +++ b/mps-interpreter/src/lang/vocabulary/repeat.rs @@ -133,12 +133,20 @@ impl MpsFunctionFactory for RepeatFunctionFactory { let inner_statement = dict.try_build_statement(tokens)?; tokens.extend(end_tokens); let mut count: Option = None; + let mut inner_done = false; if tokens.len() != 0 { // repititions specified assert_token_raw(MpsToken::Comma, tokens)?; count = Some(assert_token( |t| match t { - MpsToken::Name(n) => n.parse::().map(|d| d - 1).ok(), + MpsToken::Name(n) => n.parse::().map( + |d| if d == 0 { + inner_done = true; + 0 + } else { + d-1 + } + ).ok(), _ => None, }, MpsToken::Name("usize".into()), @@ -147,7 +155,7 @@ impl MpsFunctionFactory for RepeatFunctionFactory { } Ok(RepeatStatement { inner_statement: inner_statement.into(), - inner_done: false, + inner_done: inner_done, context: None, cache: Vec::new(), cache_position: 0, diff --git a/mps-interpreter/src/lang/vocabulary/sql_query.rs b/mps-interpreter/src/lang/vocabulary/sql_query.rs index 41a58db..c1d9934 100644 --- a/mps-interpreter/src/lang/vocabulary/sql_query.rs +++ b/mps-interpreter/src/lang/vocabulary/sql_query.rs @@ -85,7 +85,10 @@ impl Iterator for SqlStatement { match ctx.database.raw(&self.query, &mut move || { (Box::new(self_clone.clone()) as Box).into() }) { - Err(e) => return Some(Err(e)), + Err(e) => { + self.rows = Some(Vec::with_capacity(0)); + return Some(Err(e)); + }, Ok(rows) => { self.rows = Some(rows); self.get_item(false) diff --git a/mps-interpreter/src/lang/vocabulary/sql_simple_query.rs b/mps-interpreter/src/lang/vocabulary/sql_simple_query.rs index 8fb9a08..c6b554d 100644 --- a/mps-interpreter/src/lang/vocabulary/sql_simple_query.rs +++ b/mps-interpreter/src/lang/vocabulary/sql_simple_query.rs @@ -147,7 +147,10 @@ impl Iterator for SimpleSqlStatement { }), }; match query_result { - Err(e) => return Some(Err(e)), + Err(e) => { + self.rows = Some(Vec::with_capacity(0)); + return Some(Err(e)); + }, Ok(rows) => { self.rows = Some(rows); self.get_item(false) diff --git a/mps-interpreter/src/tokens/tokenizer.rs b/mps-interpreter/src/tokens/tokenizer.rs index 14cf651..0219cb3 100644 --- a/mps-interpreter/src/tokens/tokenizer.rs +++ b/mps-interpreter/src/tokens/tokenizer.rs @@ -114,7 +114,13 @@ where } ReaderStateMachine::Invalid { .. } => { let invalid_char = bigger_buf.pop().unwrap(); // invalid single char - Err(self.error(format!("Unexpected character {}", invalid_char)))?; + // clear everything, to avoid further errors + bigger_buf.clear(); + buf.clear(); + return match invalid_char { + 0 => Err(self.error(format!("EOF"))), + _ => Err(self.error(format!("character {:?} ({})", invalid_char as char, invalid_char))) + }; } _ => {} } @@ -137,7 +143,7 @@ where .map_err(|e| self.error(format!("UTF-8 encoding error: {}", e)))?; buf.push_back( MpsToken::parse_from_string(token) - .map_err(|e| self.error(format!("Invalid token {}", e)))?, + .map_err(|e| self.error(format!("invalid token {}", e)))?, ); bigger_buf.clear(); } @@ -148,8 +154,10 @@ where fn do_tracking(&mut self, input: u8) { if input as char == '\n' { self.line += 1; + self.column = 0; + } else { + self.column += 1; // TODO correctly track columns with utf-8 characters longer than one byte } - self.column += 1; // TODO correctly track columns with utf-8 characters longer than one byte } /// error factory (for ergonomics/DRY) @@ -247,7 +255,7 @@ impl ReaderStateMachine { '`' => Self::StartTickLiteral {}, '"' => Self::StartQuoteLiteral {}, ' ' => Self::EndToken {}, - '\n' | '\r' | ';' => Self::EndStatement {}, + '\n' | ';' => Self::EndStatement {}, '\0' => Self::EndOfFile {}, '(' | ')' | ',' | '=' | '<' | '>' | '.' => Self::SingleCharToken { out: input }, _ => Self::Regular { out: input }, @@ -273,7 +281,7 @@ impl ReaderStateMachine { '/' => Self::Comment { out: input }, ' ' => Self::EndToken {}, '\0' => Self::EndOfFile {}, - '\n' | '\r' | ';' => Self::EndStatement {}, + '\n' | ';' => Self::EndStatement {}, _ => Self::Regular { out: input }, }, Self::Octothorpe { .. } => match input_char { diff --git a/src/main.rs b/src/main.rs index 7f3738b..94321f9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -68,7 +68,7 @@ fn main() { // start REPL println!("Welcome to MPS interactive mode!"); println!("Run ?help for usage instructions."); - println!("End a statement with ; to execute it."); + //println!("End a statement with ; to execute it."); repl::repl(args) } } diff --git a/src/repl.rs b/src/repl.rs index 6e90416..4121e29 100644 --- a/src/repl.rs +++ b/src/repl.rs @@ -43,7 +43,13 @@ pub fn repl(args: CliArgs) { read_loop(&args, &mut state, || { match player.save_m3u8(&mut playlist_writer) { Ok(_) => {} - Err(e) => eprintln!("{}", e.message()), + Err(e) => { + eprintln!("{}", e.message()); + // consume any further errors (this shouldn't actually write anything) + while let Err(e) = player.save_m3u8(&mut playlist_writer) { + eprintln!("{}", e.message()); + } + }, } playlist_writer .flush() @@ -59,8 +65,15 @@ pub fn repl(args: CliArgs) { Err(e) => eprintln!("{}", e.message()), } } else { - for e in ctrl.check_ack() { - eprintln!("{}", e.message()); + // consume all incoming errors + let mut had_err = true; + while had_err { + let mut new_had_err = false; + for e in ctrl.check_ack() { + eprintln!("{}", e.message()); + new_had_err = true; + } + had_err = new_had_err; } } }); @@ -85,7 +98,6 @@ fn read_loop(args: &CliArgs, state: &mut ReplState, mut execute: F) let statement_result = std::str::from_utf8(state.statement_buf.as_slice()); if statement_result.is_ok() && statement_result.unwrap().starts_with("?") { repl_commands(statement_result.unwrap()); - state.writer.write(&[';' as u8]).unwrap_or(0); } else { state .writer