I am building a pretty simple parser over &[u8]. Unfortunately, when I try to convert the errors I get into anyhow errors, it informs me that the various nom Error types (nom::error::Error and nom::error::VerboseError) don't implement Display, and thus don't actually implement std::error:Error. Is there anything I can do to make these errors propagate?
Related
I often use typed holes to define functions for which I know the interface and intend to implement later. When I run cabal build, it stops after the first module it encounters with typed holes, hiding type errors that may exist in other modules.
Is there any way of typechecking a project, and only failing for typed holes after the entire project has been built and typechecked?
#chi very politely told me to Read The Docs. There seems to be two ways of configuring typed holes:
The default behaviour, which makes typed holes a compile-time error. This causes compilation to stop after the first module encountered with typed holes, hiding both type errors and typed holes in other modules.
-fdefer-typed-holes which will issue a warning upon encountering a typed hole, and go on to compile the rest of the project. If no other errors are encountered, a binary is built, with the typed holes demoted to runtime errors. On the one hand, all holes show up in the compiler output, but on the other, it is less than ideal for these to allow the build to succeed.
There is, however, a slightly hacky combination of flags that gets (almost) the desired behaviour:
-fdefer-typed-holes -Werror=typed-holes
This typechecks each module in the project, stopping for any (non-hole) type errors. If there are none in a given module, build prints out all the typed holes in the project and goes on to typecheck the rest of the project. Build only succeeds if it encounters no type errors or typed holes.
It would be even nicer if we could get type errors and typed holes in the same output, but you can't have everything.
This excerpt from the docs says it all.
A “Found hole” error usually terminates compilation, like any other type error. After all, you have omitted some code from your program.
Nevertheless, you can run and test a piece of code containing holes,
by using the -fdefer-typed-holes flag. This flag defers errors
produced by typed holes until runtime, and converts them into
compile-time warnings. These warnings can in turn be suppressed
entirely by -Wno-typed-holes.
When error occurs in Rust, most Rust standard and 3rd party libraries (e.g. anyhow) would simply print the error message to stdout/stderr. What I need is to override it with my own function. For example, call Windows API MessageBox with the location information (which file and line does it panic).
So far, I tried several methods and each lacks something.
Write my custom error, and overrides its Debug trait. The problem is that this error type needs to be able to wrap any underlying error (e.g. dyn std::error::Error), so that I could still write
fn test() -> std::result::Result<(), CustomError> {
...
if (has_windows_error) {
return Err(WindowsError(123))?;
}
if (has_io_error) {
return Err(IoError(123))?;
}
Ok(())
}
However, this means CustomError needs to implement both std::error::Error and From<std::error::Error>, which conflicts against each other.
Write my custom result type, and implement Try. This approach requires touching the experimental #![feature(try_trait_v2)].
Use std::panic::set_panic_hook(), then never use ? in the code. Instead, only immediately unwrap() all Results. This is needed because if I allow the error to bubble up, I will lose the location information in PanicInfo.
I'm relatively new to Rust, so I could have been missing many things. Option 3 is what I'm currently using, though I don't like how it forces me to abandon idiomatic coding style.
What is the cleanest, less intrusive way to implement custom error outputting currently?
Option 3 is most certainly not the way to go here. In Rust panics mean unrecoverable errors, and from my experience with the community over the last 2 years this guideline is taken pretty seriously. Moreover options 1 and 2 add pretty substantial side-effects to operations which were never meant to hide stuff like that.
Also I'm not sure what you mean by "3rd party libraries (e.g. anyhow) would simply print the error message to stdout/stderr." If your function returns an anyhow::Result<T> and an error occurs, then all that happens is that error is converted into anyhow::Error, it's not printed unless you print it.
The bottom line is that there's no "error handling framework" in Rust. Results are not special at all, in fact I encourage you to read the source code. If you want to handle a result in a certain way, then match on it and write the code to handle it. Moreover the panic handling machinery is not meant to elevate them to something like C++ exceptions. You can read more about the motivations for it here.
It sounds like what would work best for you is using anyhow or something like it, and at some point in your program you can match on a result, convert the anyhow::Error (or std::error::Error implementer of your choice) to a string and open a message box. If you want to include file and line information about where the error occurred, then that could be added to the error's message/data via the file! and line! macros provided through the standard library. This could look something like the following:
pub fn main() {
if let Err(error) = try_main() {
// show_message_box implementation not shown
show_message_box(error.to_string());
}
}
pub fn try_main() -> anyhow::Result<()> {
// code which makes extensive use of `?`
}
Note that Rust's approach to error handling is different from many other widely used languages, so it's going to require a shift in coding style. Errors are deliberately meant to be intrusive in your code so you actually handle them properly, which is something I came to greatly appreciate with time. In fact, Rust's idiosyncrasies make it a very opinionated language, so when you reach pain points I would advice against trying to solve them by using language features beyond their intended use, as that's more likely to cause additional pain points than to solve your problem.
I am rewriting a C++ program to Rust, and there is one thing that gives me an emotional rollercoaster. At first iteration it gives me, say 50 errors, then I solve them one by one, and just when I solve the last one, the compiler gives me 60 fresh errors, then I solve them and get another few tens of errors.
The last (yet) set of errors seems to be generated exclusively by the borrow checker. So why does this happen? Are there some layers or stages of the compiling process, and if yes what are they?
I want to know that, because I like predictability and dislike emotional rollercoasters (also I want to know when this adventure is going to end).
Yes, there is an order:
Syntax errors, from parsing the source code
Non-lifetime type errors, from the type checker
Lifetime errors, from the borrow checker
The first two are common to most typed languages. You need to build some kind of model of the type relationships before checking them, which will fail fast if the syntax is incorrect. In Rust, a subsequent step is to verify that all borrows are valid, once the basic type check has passed.
You can read more in the blog post, Introducing MIR
.
I'm new to antlr4 and I'm trying to make good use of antlr's ability to recover from parser errors and proceed. I find that it can proceed to visit the parse tree even when there has been a parse error and it will match a rule but sometimes not all of the rule elements are there. This causes a problem in my visitor code because my code is expecting all elements of the rule match to be there and it throws an exception.
Two options I'm thinking of:
1) after parsing, check parser.getNumberOfSyntaxErrors() > 1 and don't proceed to visit the parse tree if so. This will stop an exception being thrown, but does not give the user as good feedback as possible. antlr4 does recover nicely from errors and can get to the next independent section of what I'm trying to parse so this is stronger than what I'd like.
2) I can wrap each self.visit() in something that will catch
an exception and react accordingly. I think this would work.
But, I'm wondering if there is something in ctx or otherwise that would tell me that what's below it in the parse tree is an incomplete match?
In case it is relevant, I'm using python with antlr 4.
As you have seen ANTLR4 tries to re-synchronize the input stream to the rule structure once an error was encountered. This is usually done by trying to detect a single missing token or a single additional token. Everything else usually leads to error nodes all the way to the end of the input.
Of course, if the input cannot be parsed successfully the parse tree will be incomplete, at least from the point of the error, which might be much earlier than where the actual error is located. This happens because of variable lookahead, which may consume much of the input to find a prediction early in the parsing process (and hence this can fail early).
In fact I recommend to follow path 1). Once you got a syntax error there's not much in the parse tree you can use. It's totally up to the grammar structure what part will be parsed successfully (don't assume it would always be everything up to the error position, as I just explained).
I've been wanting to make a block type game for a while now but have never understood how to actually make one. I have googled forever and there is not much and what is there comes with a stipulation that I am not wanting to bother with (gpl license, entire code base, AND the license in any project, bleh). So I took to a forums with my problem. I did not know it, but I was trying to make a Puyo Puyo type game. With blocks dropping from the ceiling and then clearing if there's a match of 3 or more. I had no idea on how to do the matching. Which is what I wanted to know. A very nice, charming, and intelligent fellow provided me with this:
http://hastebin.com/ziyejejoxu.js
Granted, that's quite a lot, but the way he managed to code it allowed me to somewhat grasp it. However, there is a single infuriating problem. One, exactly ONE, line of code does not compile and breaks. I asked him if I could email him about it and he said okay. I haven't go a response yet so I may not be getting one so I'm taking this here. Here is how I am using the code so far. There are two parts, the play state, and the puzzle piece:
http://pastebin.com/SvMR9mMb
The program breaks in the playstate, giving this error:
source/PlayState.hx:291: characters 33-52 : Array access is not allowed on x : Int -> Int
What I have tried:
I had assumed that it was not allowed because the puzzle piece x is a float, and of course, you can't push a float into an int array. So what I did was simply in the puzzle piece first, convert the the float to an int. That did not work. THEN in the state, I switched the float to an int. That did not work. As an exercise, I attempted to convert a Flixel game to HaxeFlixel to see if I could learn anything. I probably did it wrong and did not.
So the question is: Why does that line not compile and what do I need to do to make it compile or to achieve it's intended purpose?
The syntax is wrong. push is a function, and function calls use (). [] is for array access (hence the error message).
This should work:
if (this_piece_is_in_a_match) matched_pieces.push(_i);