Changelog:
---
A lot has been going on, with more than 530 patches and 70 PRs merged since
0.7.0 last summer. In summary:
- Quite a lot of syntax improvements and changes. Checkout the latest
[cheat-sheet](https://catalalang.github.io/catala/syntax.pdf) for an overview
- Allow local `let ... equals ... in ...` definitions
- Better error messages and positions throughout
- Added the ability to directly call a scope and retrieve its outputs, like a
function
- Added disambiguation, allowing to access structure fields without specifying
the structure type each time
- Added automated resolution of operators, allowing e.g. to write just `+` in
place of all the type-specific operators `+.`, `+$`, `+@`, `+^`, etc.
- More consistent priority for operators. It is no longer allowed to write `a
and b or c` without parenthesis.
- Added and changed some operators (`date + duration` now allowed either way,
`int / int` now returns a decimal, added `duration / duration`)
- Added the ability to have variables and functions defined at
top-level (outside of any scope). See annex A of the tutorial for details.
- Added support for functions with multiple arguments
- Some big refactors in the compiler, allowing much better code sharing between
the different passes, and making it much easier to extend. Also added the
possibility to run the type-checker earlier, etc.
- Countless bug-fixes
- Improvements to our proof backend with Z3
- A tool to automatically synchronise with the upstream French law from
Legifrance
* Use the newer "pyproject.toml" for syntax highlighters
* Use venv for everything (previously, the pygment lexers were installed
globally, but more recent Python releases frown upon that. This will probably
be more stable in the long run...)
* Use one venv at the root of the project (`_python_venv/`) for both
pygments and the runtime
* Initialise this venv automatically from the Makefile (it should no longer be
necessary to run scattered `set_up.sh` scripts with mysterious interactions)
On the downsides, though:
* Only tested with Python 3.11 at the moment
* Need to remember to activate the venv (`. _python_venv/bin/activate`) from the
root for e.g. HTML literate output to work. A more manageable solution could
be for Catala to provide the lexers on-the-fly when calling `pygmentize`.
Closes#373
This forbids expressions such as `a and b or c`, avoiding the need to set an
implicit priority between `and`, `or` and `xor`, which I find error-prone.
Instead, when that appears, a message asking for explicit parentheses will be
shown to the user.
Implementation note: since that would be extremely tedious to do in the parser
directly, the parser is set to allow right-associativity without discrimination
for the logical operators, and the check is done during desugaring. This
required to explicit parentheses in the surface AST to discriminate the case
where the priority was explicit.
Command used: `sed -i 's/\([-+*/><=]=\?\)[.$@^€$]/\1/g' **/*/*.catala_*`
The overload test, of course, is kept unchanged and ensures that explicit
operators still work.
This uses the same disambiguation mechanism put in place for
structures, calling the typer on individual rules on the desugared AST
to propagate types, in order to resolve ambiguous operators like `+`
to their strongly typed counterparts (`+!`, `+.`, `+$`, `+@`, `+$`) in
the translation to scopelang.
The patch includes some normalisation of the definition of all the
operators, and classifies them based on their typing policy instead of
their arity. It also adds a little more flexibility:
- a couple new operators, like `-` on date and duration
- optional type annotation on some aggregation constructions
The `Shared_ast` lib is also lightly restructured, with the `Expr`
module split into `Type`, `Operator` and `Expr`.
Some typing errors are changed a little, because they get triggered during the
typing of the disambiguation pass, which does not specify the expected return
type (it's an expected invariant that it should not be needed for
disambiguation).
It would be possible to still specify these types during disambiguation just to
get the same errors, but since the newer ones don't appear to be clearly worse
at the moment, it has not been done.
Many changes got bundled in here and would be too tedious to separate.
Closes#330
See changes in `shared_ast/definitions.ml` to check the main point.
- the biggest change is a modification of the struct and enum types in
expressions: they are now stored as `Map`s throughout passes, and no longer
converted to indexed lists after scopelang. Their accessors are also changed,
and tuples only exist in Lcalc (they're used for closure conversion).
This implied adding some more information in the contexts, to keep the mapping
between struct fields and scope output variables. It should also be much more
robust (no longer relying on assumptions upon different orderings).
- another very pervasive change is more cosmetic: the rewrite of the main AST to
use inline records, labelling individual subfields.
- moved the checks for correct definitions and accesses of structures from
`Scope_to_dcalc` to `Typing`
- defining some new shallow iterators in module `Shared_ast.Expr`, and
factorising a few same-pass rewriting functions accordingly (closure
conversion, optimisations, etc.)
- some smaller style improvements (ensuring we use the proper compare/equal
functions instead of `=` in a few `when` closes, for example)
Quite a few changes are included here, some of which have some extra
implications visible in the language:
- adds the `Scope of { -- input_v: value; ... }` construct in the language
- handle it down the pipeline:
* `ScopeCall` in the surface AST
* `EScopeCall` in desugared and scopelang
* expressions are now traversed to detect dependencies between scopes
* transformed into a normal function call in dcalc
- defining a scope now implicitely defines a structure with the same name, with
the output variables of the scope defined as fields. This allows us to type
the return value from a scope call and access its fields easily.
* the implications are mostly in surface/name_resolution.ml code-wise
* the `Scope_out` struct that was defined in scope_to_dcalc is no longer
needed/used and the fields are no longer renamed (changes some outputs; the
explicit suffix for variables with multiple states is ignored as well)
* one benefit is that disambiguation works just like for structures when there
are conflicts on field names
* however, it's now a conflict if a scope and a structure have the same
name (side-note: issues with conflicting enum / struct names or scope
variables / subscope names were silent and are now properly reported)
- you can consequently use scope names as types for variables as well. Writing
literals is not allowed though, they can only be obtained by calling the
scope.
Remaining TODOs:
- context variables are not handled properly at the moment
- error handling on invalid calls
- tests show a small error message regression; lots of examples will need
tweaking to avoid scope/struct name or struct fields / output variable
conflicts
- add a `->` syntax to make struct field access distinct from scope output var
access, enforced with typing. This is expected to reduce confusion of users
and add a little typing precision.
- document the new syntax & implications (tutorial, cheat-sheet)
- a consequence of the changes is that subscope variables also can now be typed.
A possible future evolution / simplification would be to rewrite subscopes as
explicit scope calls early in the pipeline. That could also allow to manipulate
them as expressions (bind them in let-ins, return them...)
Also add some safeguards against bad propagation of types (e.g. checking the
arrow type of functions upon application); partly disabled at the moment since
they don't pass yet but that'll be further work.