Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: clarifications

...

A functional-programming approach to errors/diagnostics, that also is consistent with Daffodil's DSOM model and the OOLAG (object oriented lazy attribute grammar) approach works like this: You call a function or evaluate an expression to create a value. The returned object is always of the correct type, but the returned object represents either a value, a set of errors/diagnostics/warnings, or both. Attributes of the returned object will include the set of errors/diagnostics/warnings/information, a status of whether the value is okOK, or there was an error severe enough to prevent creation of a value.

Example: an xpath expression is compiled into a CompiledExpression type object. This object type should contain a boolean member named hasValue or isRunnable (or perhaps wasCompilationSuccessful()?) which is true of if compilation of the xpath succeeded. A member errorSet 'diagnostics' will be Nil if there are no errors/diagnostics/warnings/info, otherwise will contain a Set of error/diagnostic/warning/info objects. If hasValue is true, then any error/diagnostic/warning objects are not ones that prevent the CompiledExpression from being used (i.e., probably all warnings/info objects)

In general, this is the idiom for any sort of compilation step. So instead of a compilation action returning an Option[T] where None indicates failure, we get type T, and isRunnable will be true or false.(TBD: use unapply in Scala to make it possible to use Scala match-case and destructuring to determine the status.)

Runtime

The parser runtime has a return object that captures success/failure. Whether any given runtime failure is actually a failure, or just part of speculative parsing is not something we actually know in advance, which means even if we're just backtracking as part of parsing we'll be constructing diagnostic objects just in case those errors propagate up to top level. 

For example: suppose we have a choice with 3 alternatives. Suppose the data doesn't match any of the 3. The diagnostic we issue doesn't want to say that the 3rd alternative didn't match, it wants to say that no alternative matched the data, and specifically may want to say that the first alternative didn't match because of reason(s) X, the second due to reason(s) Y, and the third due to reason(s) Z.  That is, imagine we are parsing along attempting the first alternative of this choice. We encounter an error. Now this error might be suppressed because one of the subsequent alternatives might succeed, and in that case we can discard the failure reason for the first alternative. Or, this error might still be needed because if all 3 alternatives result in errors, it might be helpful as a diagnostic to see why each alternative failed.

We'll want to design this so that most of the work associated with diagnostics (constructing message strings for example, and substituting toString representations of various pieces of errant data into them) all happens at the time the diagnostic is actually issued at top level, and not at the time the diagnostic object is created. Aka,

...