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_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))
}

View file

@ -133,12 +133,20 @@ impl MpsFunctionFactory<RepeatStatement> for RepeatFunctionFactory {
let inner_statement = dict.try_build_statement(tokens)?;
tokens.extend(end_tokens);
let mut count: Option<usize> = 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::<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,
},
MpsToken::Name("usize".into()),
@ -147,7 +155,7 @@ impl MpsFunctionFactory<RepeatStatement> for RepeatFunctionFactory {
}
Ok(RepeatStatement {
inner_statement: inner_statement.into(),
inner_done: false,
inner_done: inner_done,
context: None,
cache: Vec::new(),
cache_position: 0,

View file

@ -85,7 +85,10 @@ impl Iterator for SqlStatement {
match ctx.database.raw(&self.query, &mut move || {
(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) => {
self.rows = Some(rows);
self.get_item(false)

View file

@ -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)

View file

@ -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 {

View file

@ -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)
}
}

View file

@ -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<F: FnMut()>(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