This includes a few separate changes:
- pass visibility information of declarations (depending on wether the
declaration was in a ```catala-metadata block or not)
- add reasonable hash computation functions to discriminate the interfaces. In
particular:
* Uids have a `hash` function that depends on their string, but not on their
actual uid (which is not stable between runs of the compiler) ; the existing
`hash` function and its uses have been renamed to `id`.
* The `Hash` module provides the tools to properly combine hashes, etc. While
we rely on `Hashtbl.hash` for the atoms, we take care not to use it on any
recursive structure (it relies on a bounded traversal).
- insert the hashes in the artefacts, and properly check and report those (for
OCaml)
**Remains to do**:
- Record and check the hashes in the other backends
- Provide a way to get stable inline-test outputs in the presence of module
hashes
- Provide a way to write external modules that don't break at every Catala
update.
- 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
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.
Through the syntax `var_name state state_name`.
Addresses #567, but
- requires documentation
- explicitely accessing states of the variable being defined is not allowed at
the moment (warning proposed in #567 requires a whole-expression check, which
is better done some place else entirely)
This allows for retyping after monomorphisation: a new function just extracts
the return type of the operator, without checking the operand types.
Also to avoid multiplying function arguments around the typer, the flags have
been gathered in a record that is included in the typing environment; it's ok to
give them default values as long as these are the strictest.
The primary use-case for this was to be able to run computations on a list of
structures, then return an updated list with some fields in the structures
modified : that is what we need for distribution of tax amounts among household
members, for example.
This patch has a few components:
- Addition of a test as an example for tax distributions
- Added a transformation, performed during desugaring, that -- where lists are
syntactically expected, i.e. after the `among` keyword -- turns a (syntactic)
tuple of lists into a list of tuples ("zipping" the lists)
- Arg-extremum transformation was also fixed to use an intermediate list instead
of computing the predicate twice
- For convenience, allow to bind multiple variables in most* list
operations (previously only `let in` and functions allowed it)
- Fixed the printer for tuples to differentiate them from lists
*Note: tuples are not yet allowed on the left-hand side of filters and
arg-extremums for annoying syntax conflict reasons.
As part of making tuples first-class citizens, expliciting the arity upon
function application was needed (so that a function of two args can
transparently -- in the surface language -- be applied to either two arguments
or a pair).
It was decided to actually explicit the whole type of arguments because the cost
is the same, and this is consistent with lambda definitions.
A related change done here is the replacement of the `EOp` node for operators by
an "operator application" `EAppOp` node, enforcing a pervasive invariant that
operators are always directly applied. This makes matches terser, and highlights
the fact that the treatment of operator application is almost always different
from function application in practice.
This changes the `decl_ctx` to be toplevel only, with flattened references to
uids for most elements. The module hierarchy, which is still useful in a few
places, is kept separately.
Module names are also changed to UIDs early on, and support for module aliases
has been added (needs testing).
This resolves some issues with lookup, and should be much more robust, as well
as more convenient for most lookups.
The `decl_ctx` was also extended for string ident lookups, which avoids having
to keep the desugared resolution structure available throughout the compilation
chain.
Rather than require all files to be listed on the command-line (and having to
check consistency with `> Using` directives), the main catala CLI is now a bit
more clever.
⇒ There is a new assumption that a module name definition must match the file
name (up to case and extension) — with appropriate error handling to enforce it.
In exchange, `> Using` directives are now used to more transparently lookup the
appropriate `.catala_*` interfaces and the compiled artifacts for the used modules (handling transitive dependencies), with just standard `-I` flags for when they need to be looked up in different places.