hawkw / decaf

like Java, but less so
hawkweisman.me/decaf
Other
18 stars 4 forks source link

Error Handling Architecture #23

Closed hawkw closed 10 years ago

hawkw commented 10 years ago

We need to determine how the Decaf compiler will handle errors. We need to determine how we will differentiate between fatal errors (that halt compilation) and warnings (that allow compilation to continue).

We also need to determine if dcc will continue semantic analysis after generating a fatal error, so that we can catch other errors in the program as well. It would be nice to report all of the errors in the program, rather than just the first one encountered; however, this may make some things more difficult, since, for example, type checking depends on scoping, and if we aren't able to scope the program correctly, it might confuse the type checker.

I think Scala's heap-based error management construct (Try[A]) and possibly also Futures and Promises might be useful here.

hawkw commented 10 years ago

We also need to come up with a mechanism for outputting the errors generated throughout the compilation process (from the lexer and parser as well as from semantic analysis). We should ideally come up with a mechanism for handling all of these errors in a standardized way.

Also, we should ensure that we generate errors that are formatted identically to Dr. Jumadinova's, especially because she said that she will be testing the submission for the checkpoint using a script.

hawkw commented 10 years ago

I'd love @ArcticLight's input on this one.

ArcticLight commented 10 years ago

so, here's a few basic observations that lead to a conclusion:

  1. Now that we're done with syntactic and lexical parsing, we have a static datastructure. I do not imagine that we need to do another pass through the source code, nor will we need to leverage the parsers API from Scala. This means that we're free to deal with this problem on our own terms, and we don't have to worry about the fact that Packrat might not like it.
  2. During the lexical and syntactic parsing, I'm pretty sure that any errors generated are fatal. No matter what. For instance, if we halt on an unclosed parentheses, that's it, your program is Wrong. There is no special error handling madness that needs to happen here, except that we output the error that was thrown before we entered the typechecking phase.
  3. During the typechecking phase, we're going to be implementing this as (at least in my head this is so) a recursive walk with backtracking as well as involving some sort of pending datastructure. Why do we need pending? Because class B extends A and class A calls a B static method is technically a valid program, but why would you do that is not a valid answer for us to give as to a case where compilation would fail. I.e. Error: Why would you do this? is not valid (and without Pending, we wouldn't be able to compile such a cyclic definition)

Therefore, if we're already holding a bunch of tables AND a table of compilation state while managing the compile, why not one more table? I propose a simple structure that holds pending warnings and errors. We do what we can during the recursive walk, updating the state as we go, and if there are any errors or warnings left when we're done, we print them. This also allows us to manage errors which only make sense in certain contexts, such as errors of "Unused type" or "Undeclared type" since we can push a Pending version of the error where we first see it, and then resume whatever generated the Pending error once we resolve it with another definition.

hawkw commented 10 years ago

This is kind-of-done?