- Clearly distinguish Exceptions from Errors. The only catchable exception
available in our AST is `EmptyError`, so the corresponding nodes are made less
generic, and a node `FatalError` is added
- Runtime errors are defined as a specific type in the OCaml runtime, with a
carrier exception and printing functions. These are used throughout, and
consistently by the interpreter. They always carry a position, that can be
converted to be printed with the fancy compiler location printer, or in a
simpler way from the backends.
- All operators that might be subject to an error take a position as argument,
in order to print an informative message without relying on backtraces from
the backend
--trace and --avoid-exceptions is a warning, but we want to be able to test with
the combination (in particular, api_web as forcing --trace, so we couldn't
detect its issues with exceptions).
It makes it easier to batch-set them when testing a given repo with different
sets of options. Direct flags should still be preferred in general, of course.
Module names must be capitalised (start with a capital letter), and the name of
the file on disk must match ; however, matching up to capitalisation is allowed,
i.e. the file on disk can start with a lowercase letter.
A mismatch between Clerk assuming generated module artifacts would match the
capitalised module name, and `catala depends` matching the names of files on
disk (because it would otherwise mean treating dependencies differently
depending on if they originate from modules or not) was causing "file not found"
errors later on in the compilation chain.
This patch enforces that the capitalisation of the original file name on
disk (which is always known) takes precedence in Clerk, matching the behaviour
of `catala depends` and fixing the issue. It's also actually a small
simplification in Clerk code.
This was a pending TODO: now the Catala program compiled into OCaml should
return better messages and a little more information about uncaught exceptions.
Note that this also concerns, at the moment, compiled modules called from the
Catala interpreter: in this case, it's already better than nothing, but what we
need is proper interoperation between the runtime exceptions and the interpreter
handling (`EmptyError` should already be handled properly since it is critical
to the computation flow, but "error" exceptions are left uncaught and will kill
the interpreter).
This may be part of a bigger task on unifying the output of the runtime and
toplevel, which also concerns computation traces.
Note 2: All runtime exceptions don't have a position available, which is quite
unfortunate when your program hits an error. With `OCAMLRUNPARAM=b` and if
compiled with `-g` (which should normally be the case), you can get an OCaml
backtrace but that's not very friendly. Ideas for improvement:
- The runtime could force-enable backtrace recording (`Printexc.record_backtrace
true`) to supersede the need for `OCAMLRUNPARAM`. We can also record our own
handler to print the file position and/or backtrace in the way we see fit
- The printer of OCaml code in Catala could insert line directives so that the
positions in the backtrace actually trace automatically back to the Catala
code
- If we don't want to leverage any OCaml machinery in this way, the compiler
should add position information to any operator that might fail (e.g.
divisions, date comparisons, etc.).
Note that running in trace mode might already help pinpoint the location of the
error ?
As discussed in #549
NOTE: This implements only the direct tuple member access (syntax `foo.N` with N a
number)
- It seems more efficient to wait for the general pattern-matching rewrite to
handle pattern-matching on tuples
- Until then we keep the (now obsolete) `let (x, y) = pair in x` syntax, to
leave time for updates, but we won't be documenting it
Closes#592
A new node is added in `desugared`, and translated into an exploded structure
literal during translation to `scopelang`. The main reason to put it there is
that it needs to be after disambiguation, since that is used to discover the
type of the structure that is being updated.
Ensuring messages don't print overlong lines still requires some manual work:
- if they don't contain any `Format` directives (`%` or `@`), use `"%a"
Format.pp_print_text` to turn word-wrapping on.
- otherwise replace spaces with `@ ` to mark possible cutting points, as soon
that it's possible the line will get over 80 chars (most often, this means
starting before the first `%a`)
Thanks @denismerigoux
This renames the "ScopeDef" variant from `SubScope` to `SubScopeInput`, which is
much clearer and avoids confusion with the `SubScope` elements in the surface
AST (which are really subscopes and not variables at this point).
And improves some error message by specialising depending on whether we are
dealing with a subscope or an explicit structure.
Lots of tests have a new warning because they were calling subscopes without
using their outputs. A better solution could be to mark these subscopes as
`output`, now that it's possible !
They are to become citizens of the same class if we want to allow
output-subscopes (without unnecessary complications like deconstructing and
reconstructing the same structure). And it's reasonable to assume that they
share the same namespace.
With this we should shortly collapse the (internal) ambiguity between
- `subscope.subvar`: access to a variable within a subscope
- `subscope.subfield`: access to a field of the output structure contained in a
subscope variable
With the subscope a variable, these should now become strictly equivalent, so
the plan is that the first could be removed.
- This adds a `catala depends` command that recursively tracks module dependency.
It can then be used by Clerk for linking.
- Generation of cmo object files are added for OCaml (we only built native
objects, but jsoo requires bytecode).
- Some fixes to the generation of value embed/deembed shims (related to types
coming from different modules ; add support for options ; etc.)