Fix some implementation bugs found while testing REPL
This commit is contained in:
parent
cb256f0ce4
commit
c11b681d56
7 changed files with 49 additions and 14 deletions
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
16
src/repl.rs
16
src/repl.rs
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue