Accept and parse EDN Query and Transact commands (#453)#465
Conversation
ncalexan
left a comment
There was a problem hiding this comment.
Overall this is looking good.
However, I found the expression of continuation with more: Option<Command> difficult to process. Can you fold these patches down a little, so that I can see the final form?
| } | ||
|
|
||
| #[test] | ||
| fn test_transact_parser_complete_edn() { |
There was a problem hiding this comment.
A transaction is a vector-of-vectors or a vector-of-maps, in order to handle multiple assertions. So
.t [[:db/add "t" ...]
[:db/add "r" ...]]| } | ||
|
|
||
| pub fn command(s: &str) -> Command { | ||
| let skip_spaces = skip_many(space()); |
There was a problem hiding this comment.
This is the spaces() parser from combine::char. I've found that let p = || ... and then p() is more natural than cloning the parser.
| ])) | ||
| .skip(eof()) | ||
| .parse(s) | ||
| .map(|x| x.0) |
There was a problem hiding this comment.
Eh? This seems like unnecessary whitespace.
| .and(many::<Vec<_>, _>(try(any())))); | ||
|
|
||
| let query_parser = string(QUERY_COMMAND) | ||
| .and(edn_arg_parser.clone()) |
There was a problem hiding this comment.
See my other commit with .skip and .then for avoiding these indexing operations.
|
|
||
| let edn_arg_parser = skip_spaces.clone() | ||
| .and(opening_brace_parser.clone() | ||
| .and(many::<Vec<_>, _>(try(any())))); |
There was a problem hiding this comment.
Can you explain why you need to try here? any will either consume and succeed or not consume and fail; there shouldn't be consume and fail.
There was a problem hiding this comment.
I am not sure why, but if I leave the try out, I get no output at all from the many.
| pub static HELP_COMMAND: &'static str = &"help"; | ||
| pub static OPEN_COMMAND: &'static str = &"open"; | ||
| pub static CLOSE_COMMAND: &'static str = &"close"; | ||
| pub static QUERY_COMMAND: &'static str = &"q"; |
There was a problem hiding this comment.
Can we have synonyms, ".query" for ".q", ".transact" for ".t"?
c0adac7 to
b3ff534
Compare
6489e57 to
874a10a
Compare
There must be some way that I can retain the eof() after the `then` that means I don't have to move the skip on spaces and eof Make in process command storing clearer. Add comments around in process commands. Add alternative commands for transact/t and query/q
874a10a to
e0548e9
Compare
ncalexan
left a comment
There was a problem hiding this comment.
OK, this is getting cleaner. I'd like to understand what the advantage of checking for argument counts, etc, during parsing is. Is your goal to maintain user input that parses but isn't semantically correct across invocations, allowing the user to edit their work in place?
I think that parsing and interpretation should be separate stages; and that user's should use up/down (maybe via rlwrap) to get their previous, incorrect input. That might simplify a lot of the error handling you're baking into the parser.
|
|
||
| loop { | ||
| let res = input.read_input(if more.is_some() { MORE_PROMPT } else { DEFAULT_PROMPT }); | ||
| let res = input.read_input(more.clone()); |
There was a problem hiding this comment.
I'm surprised you need this clone, since you're joining strings in read_input, not re-using them.
| Some(Command::Transact(args)) => { | ||
| Command::Transact(args + " " + &line) | ||
| }, | ||
| _ => { |
There was a problem hiding this comment.
Prefer to explicitly match Some(...) and None here, so that the compiler will tell you when you need to handle cases. I feel like there's an abstraction around continuable commands vs. non-continuable commands missing here, but it's your choice how to express this.
| Command::Transact(args + " " + &line) | ||
| }, | ||
| _ => { | ||
| try!(command(&self.buffer)) |
There was a problem hiding this comment.
Prefer ...? to try!(...); it's the modern expression in Rust. Are you really only doing this evaluation for the error result? You should consume the result of any Result, using let _ = ... if needed; the compiler should be warning you that you're dropping a result on the floor here.
| let edn_arg_parser = || spaces() | ||
| .with(try(string("[")) | ||
| .or(try(string("{"))) | ||
| .then(|d| parser(move |input| { |
There was a problem hiding this comment.
If I understand correctly, you're trying to parse any line prefixed by optional space and either [ or {. I think you can do that with:
spaces()
.with(look_ahead(string("[").or(string("{")))
.with(many(any()))Using then and a special parser like you do is ingenious but definitely not a natural expression using combine :) You might also do this as
spaces().then(many(any())).and_then(|line| {
if line.starts_with("[") || line.starts_with("{") {
Ok(...)
} else {
Err(...)
}
})but then you need to know a lot more about error handling in combine. Stick to the defined combinators for easiest use.
| pub static QUERY_COMMAND: &'static str = &"q"; | ||
| pub static TRANSACT_COMMAND: &'static str = &"t"; | ||
| pub static QUERY_COMMAND: &'static str = &"query"; | ||
| pub static ALT_QUERY_COMMAND: &'static str = &"q"; |
There was a problem hiding this comment.
If you label these SHORT_ and LONG_, your try clauses will read more clearly.
|
|
||
| #[test] | ||
| fn test_open_parser_no_args_trailing_whitespace() { | ||
| let input = ".open "; |
There was a problem hiding this comment.
I see that expect_err is in 1.17.0 stable, so we can use it -- but we need to bump
Line 19 in 8a8fced
| /// Runs the REPL interactively. | ||
| pub fn run(&mut self) { | ||
| let mut more: Option<Command> = None; | ||
| let mut more = false; |
There was a problem hiding this comment.
There is a compiler warning with this patch sequence that reveals that more is only assigned to, not read. This is vestigial?
There was a problem hiding this comment.
I thought I had removed that here, but it turns out it was done elsewhere. Removing...
| .skip(eof()) | ||
| .map(|args| { | ||
| if args.len() > 0 { | ||
| return Err(cli::ErrorKind::CommandParse(format!("Unrecognized argument {:?}", args[0])).into()); |
There was a problem hiding this comment.
There's a handy bail! macro specifically to make this type of early return more pleasant.
ncalexan
left a comment
There was a problem hiding this comment.
The commit comment is missing "r" in the "r=nalexander" part.
There is trailing whitespace throughout.
If you are done with this patch, it's good enough to land -- we can revisit the parser as we iterate.
Sorry for the delayed review!
| }))); | ||
|
|
||
| let query_parser = try(string(QUERY_COMMAND)).or(try(string(ALT_QUERY_COMMAND))) | ||
| let edn_arg_parser = || spaces() |
There was a problem hiding this comment.
I don't see any movement or discussion of #465 (comment) -- did you try and fail to improve this, or do you particularly like the expression as is?
Improving this would avoid .into_iter().collect() two places below, which is a strong sign that your types are wrong: IIUC, you're collecting Vec<String> (where each string is one character!) into a String. That's going to inefficient.
There was a problem hiding this comment.
really? I could've sworn I totally rewrote that.
Looking at it, I rewrote it blow here but didn't delete the old one. I think things might've gone wiggy in the rebasing.
| let transact_parser = try(string(TRANSACT_COMMAND)).or(try(string(ALT_TRANSACT_COMMAND))) | ||
| let transact_parser = try(string(LONG_TRANSACT_COMMAND)).or(try(string(SHORT_TRANSACT_COMMAND))) | ||
| .with(edn_arg_parser()) | ||
| .map( |x| { |
There was a problem hiding this comment.
nit: no leading space before the argument: .map(|x| { ....
3aa1e5f to
00af587
Compare
* Bump rust version number. * Use `bail` when throwing errors. * Improve edn parser. * Remove references to unused `more` flag. * Improve naming of query and transact commands.
* Send queries and transactions to mentat and output the results move outputting query and transaction results out of store and into repl * Add query and transact commands to help * Execute queries and transacts passed in at startup * Address review comments =nalexander. * Bump rust version number. * Use `bail` when throwing errors. * Improve edn parser. * Remove references to unused `more` flag. * Improve naming of query and transact commands. * Execute command line args in order * Addressing rebase issues
* Open named database OR default to in memory database if no name provided Rearrange workspace to allow import of mentat crate in cli crate Create store object inside repl when started for connecting to mentat Use provided DB name to open connection in store Accept DB name as command line arg. Open on CLI start Implement '.open' command to open desired DB from inside CLI * Implement Close command to close current DB. * Closes existing open db and opens new in memory db * Review comment: Use `combine` to parse arguments. Move over to using Result rather than enums with err * Accept and parse EDN Query and Transact commands (#453) (#465) * Parse query and transact commands * Implement is_complete for transactions and queries * Improve query parser. Am still not happy with it though. There must be some way that I can retain the eof() after the `then` that means I don't have to move the skip on spaces and eof Make in process command storing clearer. Add comments around in process commands. Add alternative commands for transact/t and query/q * Address review comments r=nalexander. * Bump rust version number. * Use `bail` when throwing errors. * Improve edn parser. * Remove references to unused `more` flag. * Improve naming of query and transact commands. * Send queries and transactions to mentat and output the results (#466) * Send queries and transactions to mentat and output the results move outputting query and transaction results out of store and into repl * Add query and transact commands to help * Execute queries and transacts passed in at startup * Address review comments =nalexander. * Bump rust version number. * Use `bail` when throwing errors. * Improve edn parser. * Remove references to unused `more` flag. * Improve naming of query and transact commands. * Execute command line args in order * Addressing rebase issues
* Open named database OR default to in memory database if no name provided Rearrange workspace to allow import of mentat crate in cli crate Create store object inside repl when started for connecting to mentat Use provided DB name to open connection in store Accept DB name as command line arg. Open on CLI start Implement '.open' command to open desired DB from inside CLI * Implement Close command to close current DB. * Closes existing open db and opens new in memory db * Review comment: Use `combine` to parse arguments. Move over to using Result rather than enums with err * Accept and parse EDN Query and Transact commands (#453) (#465) * Parse query and transact commands * Implement is_complete for transactions and queries * Improve query parser. Am still not happy with it though. There must be some way that I can retain the eof() after the `then` that means I don't have to move the skip on spaces and eof Make in process command storing clearer. Add comments around in process commands. Add alternative commands for transact/t and query/q * Address review comments r=nalexander. * Bump rust version number. * Use `bail` when throwing errors. * Improve edn parser. * Remove references to unused `more` flag. * Improve naming of query and transact commands. * Send queries and transactions to mentat and output the results (#466) * Send queries and transactions to mentat and output the results move outputting query and transaction results out of store and into repl * Add query and transact commands to help * Execute queries and transacts passed in at startup * Address review comments =nalexander. * Bump rust version number. * Use `bail` when throwing errors. * Improve edn parser. * Remove references to unused `more` flag. * Improve naming of query and transact commands. * Execute command line args in order * Addressing rebase issues
* Open named database OR default to in memory database if no name provided Rearrange workspace to allow import of mentat crate in cli crate Create store object inside repl when started for connecting to mentat Use provided DB name to open connection in store Accept DB name as command line arg. Open on CLI start Implement '.open' command to open desired DB from inside CLI * Implement Close command to close current DB. * Closes existing open db and opens new in memory db * Review comment: Use `combine` to parse arguments. Move over to using Result rather than enums with err * Accept and parse EDN Query and Transact commands (#453) (#465) * Parse query and transact commands * Implement is_complete for transactions and queries * Improve query parser. Am still not happy with it though. There must be some way that I can retain the eof() after the `then` that means I don't have to move the skip on spaces and eof Make in process command storing clearer. Add comments around in process commands. Add alternative commands for transact/t and query/q * Address review comments r=nalexander. * Bump rust version number. * Use `bail` when throwing errors. * Improve edn parser. * Remove references to unused `more` flag. * Improve naming of query and transact commands. * Send queries and transactions to mentat and output the results (#466) * Send queries and transactions to mentat and output the results move outputting query and transaction results out of store and into repl * Add query and transact commands to help * Execute queries and transacts passed in at startup * Address review comments =nalexander. * Bump rust version number. * Use `bail` when throwing errors. * Improve edn parser. * Remove references to unused `more` flag. * Improve naming of query and transact commands. * Execute command line args in order * Addressing rebase issues
* Create mentat command line. * Create tools directory containing new crate for mentat_cli. * Add simple cli with mentat prompt. * Remove rustc-serialize dependency * Open DB inside CLI (#452) (#463) * Open named database OR default to in memory database if no name provided Rearrange workspace to allow import of mentat crate in cli crate Create store object inside repl when started for connecting to mentat Use provided DB name to open connection in store Accept DB name as command line arg. Open on CLI start Implement '.open' command to open desired DB from inside CLI * Implement Close command to close current DB. * Closes existing open db and opens new in memory db * Review comment: Use `combine` to parse arguments. Move over to using Result rather than enums with err * Accept and parse EDN Query and Transact commands (#453) (#465) * Parse query and transact commands * Implement is_complete for transactions and queries * Improve query parser. Am still not happy with it though. There must be some way that I can retain the eof() after the `then` that means I don't have to move the skip on spaces and eof Make in process command storing clearer. Add comments around in process commands. Add alternative commands for transact/t and query/q * Address review comments r=nalexander. * Bump rust version number. * Use `bail` when throwing errors. * Improve edn parser. * Remove references to unused `more` flag. * Improve naming of query and transact commands. * Send queries and transactions to mentat and output the results (#466) * Send queries and transactions to mentat and output the results move outputting query and transaction results out of store and into repl * Add query and transact commands to help * Execute queries and transacts passed in at startup * Address review comments =nalexander. * Bump rust version number. * Use `bail` when throwing errors. * Improve edn parser. * Remove references to unused `more` flag. * Improve naming of query and transact commands. * Execute command line args in order * Addressing rebase issues * Exit CLI (#457) (#484) r-rnewman * Implement exit command for cli tool * Address review comments r=rnewman * Include exit commands in help * Show schema of current DB (#487) * Fixing rebase issues * addressing nit * Match updated dependencies on CLI crate and remove unused import
* Create mentat command line. * Create tools directory containing new crate for mentat_cli. * Add simple cli with mentat prompt. * Remove rustc-serialize dependency * Open DB inside CLI (mozilla#452) (mozilla#463) * Open named database OR default to in memory database if no name provided Rearrange workspace to allow import of mentat crate in cli crate Create store object inside repl when started for connecting to mentat Use provided DB name to open connection in store Accept DB name as command line arg. Open on CLI start Implement '.open' command to open desired DB from inside CLI * Implement Close command to close current DB. * Closes existing open db and opens new in memory db * Review comment: Use `combine` to parse arguments. Move over to using Result rather than enums with err * Accept and parse EDN Query and Transact commands (mozilla#453) (mozilla#465) * Parse query and transact commands * Implement is_complete for transactions and queries * Improve query parser. Am still not happy with it though. There must be some way that I can retain the eof() after the `then` that means I don't have to move the skip on spaces and eof Make in process command storing clearer. Add comments around in process commands. Add alternative commands for transact/t and query/q * Address review comments r=nalexander. * Bump rust version number. * Use `bail` when throwing errors. * Improve edn parser. * Remove references to unused `more` flag. * Improve naming of query and transact commands. * Send queries and transactions to mentat and output the results (mozilla#466) * Send queries and transactions to mentat and output the results move outputting query and transaction results out of store and into repl * Add query and transact commands to help * Execute queries and transacts passed in at startup * Address review comments =nalexander. * Bump rust version number. * Use `bail` when throwing errors. * Improve edn parser. * Remove references to unused `more` flag. * Improve naming of query and transact commands. * Execute command line args in order * Addressing rebase issues * Exit CLI (mozilla#457) (mozilla#484) r-rnewman * Implement exit command for cli tool * Address review comments r=rnewman * Include exit commands in help * Show schema of current DB (mozilla#487) * Fixing rebase issues * addressing nit * Match updated dependencies on CLI crate and remove unused import
#453
depends on #463