Fix some implementation bugs found while testing REPL

This commit is contained in:
NGnius (Graham) 2022-01-04 13:00:05 -05:00
parent cb256f0ce4
commit c11b681d56
7 changed files with 49 additions and 14 deletions

View file

@ -68,6 +68,7 @@ impl<Op: MpsOp + 'static, F: MpsFunctionFactory<Op> + 'static> BoxedMpsOpFactory
assert_token_raw(MpsToken::OpenBracket, tokens)?; assert_token_raw(MpsToken::OpenBracket, tokens)?;
assert_token_raw_back(MpsToken::CloseBracket, tokens)?; assert_token_raw_back(MpsToken::CloseBracket, tokens)?;
let func = self.op_factory.build_function_params(name, tokens, dict)?; let func = self.op_factory.build_function_params(name, tokens, dict)?;
#[cfg(debug_assertions)]
assert_empty(tokens)?; assert_empty(tokens)?;
Ok(Box::new(func)) Ok(Box::new(func))
} }

View file

@ -133,12 +133,20 @@ impl MpsFunctionFactory<RepeatStatement> for RepeatFunctionFactory {
let inner_statement = dict.try_build_statement(tokens)?; let inner_statement = dict.try_build_statement(tokens)?;
tokens.extend(end_tokens); tokens.extend(end_tokens);
let mut count: Option<usize> = None; let mut count: Option<usize> = None;
let mut inner_done = false;
if tokens.len() != 0 { if tokens.len() != 0 {
// repititions specified // repititions specified
assert_token_raw(MpsToken::Comma, tokens)?; assert_token_raw(MpsToken::Comma, tokens)?;
count = Some(assert_token( count = Some(assert_token(
|t| match t { |t| match t {
MpsToken::Name(n) => n.parse::<usize>().map(|d| d - 1).ok(), MpsToken::Name(n) => n.parse::<usize>().map(
|d| if d == 0 {
inner_done = true;
0
} else {
d-1
}
).ok(),
_ => None, _ => None,
}, },
MpsToken::Name("usize".into()), MpsToken::Name("usize".into()),
@ -147,7 +155,7 @@ impl MpsFunctionFactory<RepeatStatement> for RepeatFunctionFactory {
} }
Ok(RepeatStatement { Ok(RepeatStatement {
inner_statement: inner_statement.into(), inner_statement: inner_statement.into(),
inner_done: false, inner_done: inner_done,
context: None, context: None,
cache: Vec::new(), cache: Vec::new(),
cache_position: 0, cache_position: 0,

View file

@ -85,7 +85,10 @@ impl Iterator for SqlStatement {
match ctx.database.raw(&self.query, &mut move || { match ctx.database.raw(&self.query, &mut move || {
(Box::new(self_clone.clone()) as Box<dyn MpsOp>).into() (Box::new(self_clone.clone()) as Box<dyn MpsOp>).into()
}) { }) {
Err(e) => return Some(Err(e)), Err(e) => {
self.rows = Some(Vec::with_capacity(0));
return Some(Err(e));
},
Ok(rows) => { Ok(rows) => {
self.rows = Some(rows); self.rows = Some(rows);
self.get_item(false) self.get_item(false)

View file

@ -147,7 +147,10 @@ impl Iterator for SimpleSqlStatement {
}), }),
}; };
match query_result { match query_result {
Err(e) => return Some(Err(e)), Err(e) => {
self.rows = Some(Vec::with_capacity(0));
return Some(Err(e));
},
Ok(rows) => { Ok(rows) => {
self.rows = Some(rows); self.rows = Some(rows);
self.get_item(false) self.get_item(false)

View file

@ -114,7 +114,13 @@ where
} }
ReaderStateMachine::Invalid { .. } => { ReaderStateMachine::Invalid { .. } => {
let invalid_char = bigger_buf.pop().unwrap(); // invalid single char 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)))?; .map_err(|e| self.error(format!("UTF-8 encoding error: {}", e)))?;
buf.push_back( buf.push_back(
MpsToken::parse_from_string(token) 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(); bigger_buf.clear();
} }
@ -148,9 +154,11 @@ where
fn do_tracking(&mut self, input: u8) { fn do_tracking(&mut self, input: u8) {
if input as char == '\n' { if input as char == '\n' {
self.line += 1; 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) /// error factory (for ergonomics/DRY)
fn error(&self, item: String) -> ParseError { fn error(&self, item: String) -> ParseError {
@ -247,7 +255,7 @@ impl ReaderStateMachine {
'`' => Self::StartTickLiteral {}, '`' => Self::StartTickLiteral {},
'"' => Self::StartQuoteLiteral {}, '"' => Self::StartQuoteLiteral {},
' ' => Self::EndToken {}, ' ' => Self::EndToken {},
'\n' | '\r' | ';' => Self::EndStatement {}, '\n' | ';' => Self::EndStatement {},
'\0' => Self::EndOfFile {}, '\0' => Self::EndOfFile {},
'(' | ')' | ',' | '=' | '<' | '>' | '.' => Self::SingleCharToken { out: input }, '(' | ')' | ',' | '=' | '<' | '>' | '.' => Self::SingleCharToken { out: input },
_ => Self::Regular { out: input }, _ => Self::Regular { out: input },
@ -273,7 +281,7 @@ impl ReaderStateMachine {
'/' => Self::Comment { out: input }, '/' => Self::Comment { out: input },
' ' => Self::EndToken {}, ' ' => Self::EndToken {},
'\0' => Self::EndOfFile {}, '\0' => Self::EndOfFile {},
'\n' | '\r' | ';' => Self::EndStatement {}, '\n' | ';' => Self::EndStatement {},
_ => Self::Regular { out: input }, _ => Self::Regular { out: input },
}, },
Self::Octothorpe { .. } => match input_char { Self::Octothorpe { .. } => match input_char {

View file

@ -68,7 +68,7 @@ fn main() {
// start REPL // start REPL
println!("Welcome to MPS interactive mode!"); println!("Welcome to MPS interactive mode!");
println!("Run ?help for usage instructions."); 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) repl::repl(args)
} }
} }

View file

@ -43,7 +43,13 @@ pub fn repl(args: CliArgs) {
read_loop(&args, &mut state, || { read_loop(&args, &mut state, || {
match player.save_m3u8(&mut playlist_writer) { match player.save_m3u8(&mut playlist_writer) {
Ok(_) => {} 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 playlist_writer
.flush() .flush()
@ -59,8 +65,15 @@ pub fn repl(args: CliArgs) {
Err(e) => eprintln!("{}", e.message()), Err(e) => eprintln!("{}", e.message()),
} }
} else { } else {
// consume all incoming errors
let mut had_err = true;
while had_err {
let mut new_had_err = false;
for e in ctrl.check_ack() { for e in ctrl.check_ack() {
eprintln!("{}", e.message()); eprintln!("{}", e.message());
new_had_err = true;
}
had_err = new_had_err;
} }
} }
}); });
@ -85,7 +98,6 @@ fn read_loop<F: FnMut()>(args: &CliArgs, state: &mut ReplState, mut execute: F)
let statement_result = std::str::from_utf8(state.statement_buf.as_slice()); let statement_result = std::str::from_utf8(state.statement_buf.as_slice());
if statement_result.is_ok() && statement_result.unwrap().starts_with("?") { if statement_result.is_ok() && statement_result.unwrap().starts_with("?") {
repl_commands(statement_result.unwrap()); repl_commands(statement_result.unwrap());
state.writer.write(&[';' as u8]).unwrap_or(0);
} else { } else {
state state
.writer .writer