2022-07-28 11:36:36 +03:00
|
|
|
(* This file is part of the Catala compiler, a specification language for tax
|
|
|
|
and social benefits computation rules. Copyright (C) 2020-2022 Inria,
|
|
|
|
contributor: Denis Merigoux <denis.merigoux@inria.fr>, Alain Delaët-Tixeuil
|
|
|
|
<alain.delaet--tixeuil@inria.fr>, Louis Gesbert <louis.gesbert@inria.fr>
|
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
|
|
use this file except in compliance with the License. You may obtain a copy of
|
|
|
|
the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
|
|
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
|
|
License for the specific language governing permissions and limitations under
|
|
|
|
the License. *)
|
|
|
|
|
2022-11-21 12:46:17 +03:00
|
|
|
open Catala_utils
|
2022-08-22 19:53:30 +03:00
|
|
|
open Definitions
|
2022-07-28 11:36:36 +03:00
|
|
|
|
2022-08-12 18:59:49 +03:00
|
|
|
(** Functions handling the types of [shared_ast] *)
|
2022-07-28 11:36:36 +03:00
|
|
|
|
2022-08-17 12:49:16 +03:00
|
|
|
(* Basic block constructors *)
|
|
|
|
|
Swap boxing and annotations in expressions
This was the only reasonable solution I found to the issue raised
[here](https://github.com/CatalaLang/catala/pull/334#discussion_r987175884).
This was a pretty tedious rewrite, but it should now ensure we are doing things
correctly. As a bonus, the "smart" expression constructors are now used
everywhere to build expressions (so another refactoring like this one should be
much easier) and this makes the code overall feel more
straightforward (`Bindlib.box_apply` or `let+` no longer need to be visible!)
---
Basically, we were using values of type `gexpr box = naked_gexpr marked box`
throughout when (re-)building expressions. This was done 99% of the time by
using `Bindlib.box_apply add_mark naked_e` right after building `naked_e`. In
lots of places, we needed to recover the annotation of this expression later on,
typically to build its parent term (to inherit the position, or build the type).
Since it wasn't always possible to wrap these uses within `box_apply` (esp. as
bindlib boxes aren't a monad), here and there we had to call `Bindlib.unbox`,
just to recover the position or type. This had the very unpleasant effect of
forcing the resolution of the whole box (including applying any stored closures)
to reach the top-level annotation which isn't even dependant on specific
variable bindings. Then, generally, throwing away the result.
Therefore, the change proposed here transforms
- `naked_gexpr marked Bindlib.box` into
- `naked_gexpr Bindlib.box marked` (aliased to `boxed_gexpr` or `gexpr boxed` for
convenience)
This means only
1. not fitting the mark into the box right away when building, and
2. accessing the top-level mark directly without unboxing
The functions for building terms from module `Shared_ast.Expr` could be changed
easily. But then they needed to be consistently used throughout, without
manually building terms through `Bindlib.apply_box` -- which covers most of the
changes in this patch.
`Expr.Box.inj` is provided to swap back to a box, before binding for example.
Additionally, this gives a 40% speedup on `make -C examples pass_all_tests`,
which hints at the amount of unnecessary work we were doing --'
2022-10-06 20:13:45 +03:00
|
|
|
module Box = struct
|
|
|
|
module B = Bindlib
|
2022-07-28 11:36:36 +03:00
|
|
|
|
Swap boxing and annotations in expressions
This was the only reasonable solution I found to the issue raised
[here](https://github.com/CatalaLang/catala/pull/334#discussion_r987175884).
This was a pretty tedious rewrite, but it should now ensure we are doing things
correctly. As a bonus, the "smart" expression constructors are now used
everywhere to build expressions (so another refactoring like this one should be
much easier) and this makes the code overall feel more
straightforward (`Bindlib.box_apply` or `let+` no longer need to be visible!)
---
Basically, we were using values of type `gexpr box = naked_gexpr marked box`
throughout when (re-)building expressions. This was done 99% of the time by
using `Bindlib.box_apply add_mark naked_e` right after building `naked_e`. In
lots of places, we needed to recover the annotation of this expression later on,
typically to build its parent term (to inherit the position, or build the type).
Since it wasn't always possible to wrap these uses within `box_apply` (esp. as
bindlib boxes aren't a monad), here and there we had to call `Bindlib.unbox`,
just to recover the position or type. This had the very unpleasant effect of
forcing the resolution of the whole box (including applying any stored closures)
to reach the top-level annotation which isn't even dependant on specific
variable bindings. Then, generally, throwing away the result.
Therefore, the change proposed here transforms
- `naked_gexpr marked Bindlib.box` into
- `naked_gexpr Bindlib.box marked` (aliased to `boxed_gexpr` or `gexpr boxed` for
convenience)
This means only
1. not fitting the mark into the box right away when building, and
2. accessing the top-level mark directly without unboxing
The functions for building terms from module `Shared_ast.Expr` could be changed
easily. But then they needed to be consistently used throughout, without
manually building terms through `Bindlib.apply_box` -- which covers most of the
changes in this patch.
`Expr.Box.inj` is provided to swap back to a box, before binding for example.
Additionally, this gives a 40% speedup on `make -C examples pass_all_tests`,
which hints at the amount of unnecessary work we were doing --'
2022-10-06 20:13:45 +03:00
|
|
|
let app0 x mark = B.box x, mark
|
|
|
|
let app1 (xb, m) f mark = B.box_apply (fun x -> f (x, m)) xb, mark
|
2022-07-28 11:36:36 +03:00
|
|
|
|
Swap boxing and annotations in expressions
This was the only reasonable solution I found to the issue raised
[here](https://github.com/CatalaLang/catala/pull/334#discussion_r987175884).
This was a pretty tedious rewrite, but it should now ensure we are doing things
correctly. As a bonus, the "smart" expression constructors are now used
everywhere to build expressions (so another refactoring like this one should be
much easier) and this makes the code overall feel more
straightforward (`Bindlib.box_apply` or `let+` no longer need to be visible!)
---
Basically, we were using values of type `gexpr box = naked_gexpr marked box`
throughout when (re-)building expressions. This was done 99% of the time by
using `Bindlib.box_apply add_mark naked_e` right after building `naked_e`. In
lots of places, we needed to recover the annotation of this expression later on,
typically to build its parent term (to inherit the position, or build the type).
Since it wasn't always possible to wrap these uses within `box_apply` (esp. as
bindlib boxes aren't a monad), here and there we had to call `Bindlib.unbox`,
just to recover the position or type. This had the very unpleasant effect of
forcing the resolution of the whole box (including applying any stored closures)
to reach the top-level annotation which isn't even dependant on specific
variable bindings. Then, generally, throwing away the result.
Therefore, the change proposed here transforms
- `naked_gexpr marked Bindlib.box` into
- `naked_gexpr Bindlib.box marked` (aliased to `boxed_gexpr` or `gexpr boxed` for
convenience)
This means only
1. not fitting the mark into the box right away when building, and
2. accessing the top-level mark directly without unboxing
The functions for building terms from module `Shared_ast.Expr` could be changed
easily. But then they needed to be consistently used throughout, without
manually building terms through `Bindlib.apply_box` -- which covers most of the
changes in this patch.
`Expr.Box.inj` is provided to swap back to a box, before binding for example.
Additionally, this gives a 40% speedup on `make -C examples pass_all_tests`,
which hints at the amount of unnecessary work we were doing --'
2022-10-06 20:13:45 +03:00
|
|
|
let app2 (xb1, m1) (xb2, m2) f mark =
|
|
|
|
B.box_apply2 (fun x1 x2 -> f (x1, m1) (x2, m2)) xb1 xb2, mark
|
2022-07-28 11:36:36 +03:00
|
|
|
|
Swap boxing and annotations in expressions
This was the only reasonable solution I found to the issue raised
[here](https://github.com/CatalaLang/catala/pull/334#discussion_r987175884).
This was a pretty tedious rewrite, but it should now ensure we are doing things
correctly. As a bonus, the "smart" expression constructors are now used
everywhere to build expressions (so another refactoring like this one should be
much easier) and this makes the code overall feel more
straightforward (`Bindlib.box_apply` or `let+` no longer need to be visible!)
---
Basically, we were using values of type `gexpr box = naked_gexpr marked box`
throughout when (re-)building expressions. This was done 99% of the time by
using `Bindlib.box_apply add_mark naked_e` right after building `naked_e`. In
lots of places, we needed to recover the annotation of this expression later on,
typically to build its parent term (to inherit the position, or build the type).
Since it wasn't always possible to wrap these uses within `box_apply` (esp. as
bindlib boxes aren't a monad), here and there we had to call `Bindlib.unbox`,
just to recover the position or type. This had the very unpleasant effect of
forcing the resolution of the whole box (including applying any stored closures)
to reach the top-level annotation which isn't even dependant on specific
variable bindings. Then, generally, throwing away the result.
Therefore, the change proposed here transforms
- `naked_gexpr marked Bindlib.box` into
- `naked_gexpr Bindlib.box marked` (aliased to `boxed_gexpr` or `gexpr boxed` for
convenience)
This means only
1. not fitting the mark into the box right away when building, and
2. accessing the top-level mark directly without unboxing
The functions for building terms from module `Shared_ast.Expr` could be changed
easily. But then they needed to be consistently used throughout, without
manually building terms through `Bindlib.apply_box` -- which covers most of the
changes in this patch.
`Expr.Box.inj` is provided to swap back to a box, before binding for example.
Additionally, this gives a 40% speedup on `make -C examples pass_all_tests`,
which hints at the amount of unnecessary work we were doing --'
2022-10-06 20:13:45 +03:00
|
|
|
let app3 (xb1, m1) (xb2, m2) (xb3, m3) f mark =
|
|
|
|
( B.box_apply3 (fun x1 x2 x3 -> f (x1, m1) (x2, m2) (x3, m3)) xb1 xb2 xb3,
|
|
|
|
mark )
|
2022-07-28 11:36:36 +03:00
|
|
|
|
Swap boxing and annotations in expressions
This was the only reasonable solution I found to the issue raised
[here](https://github.com/CatalaLang/catala/pull/334#discussion_r987175884).
This was a pretty tedious rewrite, but it should now ensure we are doing things
correctly. As a bonus, the "smart" expression constructors are now used
everywhere to build expressions (so another refactoring like this one should be
much easier) and this makes the code overall feel more
straightforward (`Bindlib.box_apply` or `let+` no longer need to be visible!)
---
Basically, we were using values of type `gexpr box = naked_gexpr marked box`
throughout when (re-)building expressions. This was done 99% of the time by
using `Bindlib.box_apply add_mark naked_e` right after building `naked_e`. In
lots of places, we needed to recover the annotation of this expression later on,
typically to build its parent term (to inherit the position, or build the type).
Since it wasn't always possible to wrap these uses within `box_apply` (esp. as
bindlib boxes aren't a monad), here and there we had to call `Bindlib.unbox`,
just to recover the position or type. This had the very unpleasant effect of
forcing the resolution of the whole box (including applying any stored closures)
to reach the top-level annotation which isn't even dependant on specific
variable bindings. Then, generally, throwing away the result.
Therefore, the change proposed here transforms
- `naked_gexpr marked Bindlib.box` into
- `naked_gexpr Bindlib.box marked` (aliased to `boxed_gexpr` or `gexpr boxed` for
convenience)
This means only
1. not fitting the mark into the box right away when building, and
2. accessing the top-level mark directly without unboxing
The functions for building terms from module `Shared_ast.Expr` could be changed
easily. But then they needed to be consistently used throughout, without
manually building terms through `Bindlib.apply_box` -- which covers most of the
changes in this patch.
`Expr.Box.inj` is provided to swap back to a box, before binding for example.
Additionally, this gives a 40% speedup on `make -C examples pass_all_tests`,
which hints at the amount of unnecessary work we were doing --'
2022-10-06 20:13:45 +03:00
|
|
|
let appn xmbl f mark =
|
|
|
|
let xbl, ml = List.split xmbl in
|
|
|
|
B.box_apply (fun xl -> f (List.combine xl ml)) (B.box_list xbl), mark
|
2022-07-28 11:36:36 +03:00
|
|
|
|
Swap boxing and annotations in expressions
This was the only reasonable solution I found to the issue raised
[here](https://github.com/CatalaLang/catala/pull/334#discussion_r987175884).
This was a pretty tedious rewrite, but it should now ensure we are doing things
correctly. As a bonus, the "smart" expression constructors are now used
everywhere to build expressions (so another refactoring like this one should be
much easier) and this makes the code overall feel more
straightforward (`Bindlib.box_apply` or `let+` no longer need to be visible!)
---
Basically, we were using values of type `gexpr box = naked_gexpr marked box`
throughout when (re-)building expressions. This was done 99% of the time by
using `Bindlib.box_apply add_mark naked_e` right after building `naked_e`. In
lots of places, we needed to recover the annotation of this expression later on,
typically to build its parent term (to inherit the position, or build the type).
Since it wasn't always possible to wrap these uses within `box_apply` (esp. as
bindlib boxes aren't a monad), here and there we had to call `Bindlib.unbox`,
just to recover the position or type. This had the very unpleasant effect of
forcing the resolution of the whole box (including applying any stored closures)
to reach the top-level annotation which isn't even dependant on specific
variable bindings. Then, generally, throwing away the result.
Therefore, the change proposed here transforms
- `naked_gexpr marked Bindlib.box` into
- `naked_gexpr Bindlib.box marked` (aliased to `boxed_gexpr` or `gexpr boxed` for
convenience)
This means only
1. not fitting the mark into the box right away when building, and
2. accessing the top-level mark directly without unboxing
The functions for building terms from module `Shared_ast.Expr` could be changed
easily. But then they needed to be consistently used throughout, without
manually building terms through `Bindlib.apply_box` -- which covers most of the
changes in this patch.
`Expr.Box.inj` is provided to swap back to a box, before binding for example.
Additionally, this gives a 40% speedup on `make -C examples pass_all_tests`,
which hints at the amount of unnecessary work we were doing --'
2022-10-06 20:13:45 +03:00
|
|
|
let app1n (xb0, m0) xmbl f mark =
|
|
|
|
let xbl, ml = List.split xmbl in
|
|
|
|
( B.box_apply2
|
|
|
|
(fun x0 xl -> f (x0, m0) (List.combine xl ml))
|
|
|
|
xb0 (B.box_list xbl),
|
|
|
|
mark )
|
2022-07-28 11:36:36 +03:00
|
|
|
|
Swap boxing and annotations in expressions
This was the only reasonable solution I found to the issue raised
[here](https://github.com/CatalaLang/catala/pull/334#discussion_r987175884).
This was a pretty tedious rewrite, but it should now ensure we are doing things
correctly. As a bonus, the "smart" expression constructors are now used
everywhere to build expressions (so another refactoring like this one should be
much easier) and this makes the code overall feel more
straightforward (`Bindlib.box_apply` or `let+` no longer need to be visible!)
---
Basically, we were using values of type `gexpr box = naked_gexpr marked box`
throughout when (re-)building expressions. This was done 99% of the time by
using `Bindlib.box_apply add_mark naked_e` right after building `naked_e`. In
lots of places, we needed to recover the annotation of this expression later on,
typically to build its parent term (to inherit the position, or build the type).
Since it wasn't always possible to wrap these uses within `box_apply` (esp. as
bindlib boxes aren't a monad), here and there we had to call `Bindlib.unbox`,
just to recover the position or type. This had the very unpleasant effect of
forcing the resolution of the whole box (including applying any stored closures)
to reach the top-level annotation which isn't even dependant on specific
variable bindings. Then, generally, throwing away the result.
Therefore, the change proposed here transforms
- `naked_gexpr marked Bindlib.box` into
- `naked_gexpr Bindlib.box marked` (aliased to `boxed_gexpr` or `gexpr boxed` for
convenience)
This means only
1. not fitting the mark into the box right away when building, and
2. accessing the top-level mark directly without unboxing
The functions for building terms from module `Shared_ast.Expr` could be changed
easily. But then they needed to be consistently used throughout, without
manually building terms through `Bindlib.apply_box` -- which covers most of the
changes in this patch.
`Expr.Box.inj` is provided to swap back to a box, before binding for example.
Additionally, this gives a 40% speedup on `make -C examples pass_all_tests`,
which hints at the amount of unnecessary work we were doing --'
2022-10-06 20:13:45 +03:00
|
|
|
let app2n (xb0, m0) (xb1, m1) xmbl f mark =
|
|
|
|
let xbl, ml = List.split xmbl in
|
|
|
|
( B.box_apply3
|
|
|
|
(fun x0 x1 xl -> f (x0, m0) (x1, m1) (List.combine xl ml))
|
|
|
|
xb0 xb1 (B.box_list xbl),
|
|
|
|
mark )
|
2022-07-28 11:36:36 +03:00
|
|
|
|
2022-10-21 16:33:05 +03:00
|
|
|
let lift : ('a, 't) boxed_gexpr -> ('a, 't) gexpr B.box =
|
2023-05-17 16:44:57 +03:00
|
|
|
fun em -> B.box_apply (fun e -> Mark.add (Mark.get em) e) (Mark.remove em)
|
2022-10-21 16:33:05 +03:00
|
|
|
|
2022-11-21 12:12:45 +03:00
|
|
|
module LiftStruct = Bindlib.Lift (StructField.Map)
|
2022-10-21 16:33:05 +03:00
|
|
|
|
|
|
|
let lift_struct = LiftStruct.lift_box
|
|
|
|
|
2022-11-21 12:12:45 +03:00
|
|
|
module LiftEnum = Bindlib.Lift (EnumConstructor.Map)
|
2022-10-21 16:33:05 +03:00
|
|
|
|
|
|
|
let lift_enum = LiftEnum.lift_box
|
|
|
|
|
2022-11-21 12:12:45 +03:00
|
|
|
module LiftScopeVars = Bindlib.Lift (ScopeVar.Map)
|
2022-10-21 16:33:05 +03:00
|
|
|
|
|
|
|
let lift_scope_vars = LiftScopeVars.lift_box
|
2023-04-14 15:18:28 +03:00
|
|
|
|
|
|
|
module Ren = struct
|
|
|
|
module Set = Set.Make (String)
|
|
|
|
|
|
|
|
type ctxt = Set.t
|
|
|
|
|
|
|
|
let skip_constant_binders = true
|
|
|
|
let reset_context_for_closed_terms = true
|
|
|
|
let constant_binder_name = None
|
|
|
|
let empty_ctxt = Set.empty
|
|
|
|
let reserve_name n s = Set.add n s
|
|
|
|
let new_name n s = n, Set.add n s
|
|
|
|
end
|
|
|
|
|
|
|
|
module Ctx = Bindlib.Ctxt (Ren)
|
|
|
|
|
|
|
|
let fv b = Ren.Set.elements (Ctx.free_vars b)
|
|
|
|
|
|
|
|
let assert_closed b =
|
|
|
|
match fv b with
|
|
|
|
| [] -> ()
|
|
|
|
| [h] ->
|
2023-06-13 12:27:45 +03:00
|
|
|
Message.raise_internal_error
|
2023-04-14 15:18:28 +03:00
|
|
|
"The boxed term is not closed the variable %s is free in the global \
|
|
|
|
context"
|
|
|
|
h
|
|
|
|
| l ->
|
2023-06-13 12:27:45 +03:00
|
|
|
Message.raise_internal_error
|
2023-04-14 15:18:28 +03:00
|
|
|
"The boxed term is not closed the variables %a is free in the global \
|
|
|
|
context"
|
|
|
|
(Format.pp_print_list
|
|
|
|
~pp_sep:(fun fmt () -> Format.pp_print_string fmt "; ")
|
|
|
|
Format.pp_print_string)
|
|
|
|
l
|
Swap boxing and annotations in expressions
This was the only reasonable solution I found to the issue raised
[here](https://github.com/CatalaLang/catala/pull/334#discussion_r987175884).
This was a pretty tedious rewrite, but it should now ensure we are doing things
correctly. As a bonus, the "smart" expression constructors are now used
everywhere to build expressions (so another refactoring like this one should be
much easier) and this makes the code overall feel more
straightforward (`Bindlib.box_apply` or `let+` no longer need to be visible!)
---
Basically, we were using values of type `gexpr box = naked_gexpr marked box`
throughout when (re-)building expressions. This was done 99% of the time by
using `Bindlib.box_apply add_mark naked_e` right after building `naked_e`. In
lots of places, we needed to recover the annotation of this expression later on,
typically to build its parent term (to inherit the position, or build the type).
Since it wasn't always possible to wrap these uses within `box_apply` (esp. as
bindlib boxes aren't a monad), here and there we had to call `Bindlib.unbox`,
just to recover the position or type. This had the very unpleasant effect of
forcing the resolution of the whole box (including applying any stored closures)
to reach the top-level annotation which isn't even dependant on specific
variable bindings. Then, generally, throwing away the result.
Therefore, the change proposed here transforms
- `naked_gexpr marked Bindlib.box` into
- `naked_gexpr Bindlib.box marked` (aliased to `boxed_gexpr` or `gexpr boxed` for
convenience)
This means only
1. not fitting the mark into the box right away when building, and
2. accessing the top-level mark directly without unboxing
The functions for building terms from module `Shared_ast.Expr` could be changed
easily. But then they needed to be consistently used throughout, without
manually building terms through `Bindlib.apply_box` -- which covers most of the
changes in this patch.
`Expr.Box.inj` is provided to swap back to a box, before binding for example.
Additionally, this gives a 40% speedup on `make -C examples pass_all_tests`,
which hints at the amount of unnecessary work we were doing --'
2022-10-06 20:13:45 +03:00
|
|
|
end
|
|
|
|
|
2022-10-21 16:33:05 +03:00
|
|
|
let bind vars e = Bindlib.bind_mvar vars (Box.lift e)
|
Swap boxing and annotations in expressions
This was the only reasonable solution I found to the issue raised
[here](https://github.com/CatalaLang/catala/pull/334#discussion_r987175884).
This was a pretty tedious rewrite, but it should now ensure we are doing things
correctly. As a bonus, the "smart" expression constructors are now used
everywhere to build expressions (so another refactoring like this one should be
much easier) and this makes the code overall feel more
straightforward (`Bindlib.box_apply` or `let+` no longer need to be visible!)
---
Basically, we were using values of type `gexpr box = naked_gexpr marked box`
throughout when (re-)building expressions. This was done 99% of the time by
using `Bindlib.box_apply add_mark naked_e` right after building `naked_e`. In
lots of places, we needed to recover the annotation of this expression later on,
typically to build its parent term (to inherit the position, or build the type).
Since it wasn't always possible to wrap these uses within `box_apply` (esp. as
bindlib boxes aren't a monad), here and there we had to call `Bindlib.unbox`,
just to recover the position or type. This had the very unpleasant effect of
forcing the resolution of the whole box (including applying any stored closures)
to reach the top-level annotation which isn't even dependant on specific
variable bindings. Then, generally, throwing away the result.
Therefore, the change proposed here transforms
- `naked_gexpr marked Bindlib.box` into
- `naked_gexpr Bindlib.box marked` (aliased to `boxed_gexpr` or `gexpr boxed` for
convenience)
This means only
1. not fitting the mark into the box right away when building, and
2. accessing the top-level mark directly without unboxing
The functions for building terms from module `Shared_ast.Expr` could be changed
easily. But then they needed to be consistently used throughout, without
manually building terms through `Bindlib.apply_box` -- which covers most of the
changes in this patch.
`Expr.Box.inj` is provided to swap back to a box, before binding for example.
Additionally, this gives a 40% speedup on `make -C examples pass_all_tests`,
which hints at the amount of unnecessary work we were doing --'
2022-10-06 20:13:45 +03:00
|
|
|
|
|
|
|
let subst binder vars =
|
2023-05-17 16:44:57 +03:00
|
|
|
Bindlib.msubst binder (Array.of_list (List.map Mark.remove vars))
|
2022-07-28 11:36:36 +03:00
|
|
|
|
2023-05-17 16:44:57 +03:00
|
|
|
let evar v mark = Mark.add mark (Bindlib.box_var v)
|
2023-08-31 11:07:57 +03:00
|
|
|
let eexternal ~name mark = Mark.add mark (Bindlib.box (EExternal { name }))
|
2022-11-17 19:13:35 +03:00
|
|
|
let etuple args = Box.appn args @@ fun args -> ETuple args
|
2022-07-28 11:36:36 +03:00
|
|
|
|
2022-11-17 19:13:35 +03:00
|
|
|
let etupleaccess e index size =
|
|
|
|
assert (index < size);
|
|
|
|
Box.app1 e @@ fun e -> ETupleAccess { e; index; size }
|
Swap boxing and annotations in expressions
This was the only reasonable solution I found to the issue raised
[here](https://github.com/CatalaLang/catala/pull/334#discussion_r987175884).
This was a pretty tedious rewrite, but it should now ensure we are doing things
correctly. As a bonus, the "smart" expression constructors are now used
everywhere to build expressions (so another refactoring like this one should be
much easier) and this makes the code overall feel more
straightforward (`Bindlib.box_apply` or `let+` no longer need to be visible!)
---
Basically, we were using values of type `gexpr box = naked_gexpr marked box`
throughout when (re-)building expressions. This was done 99% of the time by
using `Bindlib.box_apply add_mark naked_e` right after building `naked_e`. In
lots of places, we needed to recover the annotation of this expression later on,
typically to build its parent term (to inherit the position, or build the type).
Since it wasn't always possible to wrap these uses within `box_apply` (esp. as
bindlib boxes aren't a monad), here and there we had to call `Bindlib.unbox`,
just to recover the position or type. This had the very unpleasant effect of
forcing the resolution of the whole box (including applying any stored closures)
to reach the top-level annotation which isn't even dependant on specific
variable bindings. Then, generally, throwing away the result.
Therefore, the change proposed here transforms
- `naked_gexpr marked Bindlib.box` into
- `naked_gexpr Bindlib.box marked` (aliased to `boxed_gexpr` or `gexpr boxed` for
convenience)
This means only
1. not fitting the mark into the box right away when building, and
2. accessing the top-level mark directly without unboxing
The functions for building terms from module `Shared_ast.Expr` could be changed
easily. But then they needed to be consistently used throughout, without
manually building terms through `Bindlib.apply_box` -- which covers most of the
changes in this patch.
`Expr.Box.inj` is provided to swap back to a box, before binding for example.
Additionally, this gives a 40% speedup on `make -C examples pass_all_tests`,
which hints at the amount of unnecessary work we were doing --'
2022-10-06 20:13:45 +03:00
|
|
|
|
|
|
|
let earray args = Box.appn args @@ fun args -> EArray args
|
2023-05-17 16:44:57 +03:00
|
|
|
let elit l mark = Mark.add mark (Bindlib.box (ELit l))
|
Swap boxing and annotations in expressions
This was the only reasonable solution I found to the issue raised
[here](https://github.com/CatalaLang/catala/pull/334#discussion_r987175884).
This was a pretty tedious rewrite, but it should now ensure we are doing things
correctly. As a bonus, the "smart" expression constructors are now used
everywhere to build expressions (so another refactoring like this one should be
much easier) and this makes the code overall feel more
straightforward (`Bindlib.box_apply` or `let+` no longer need to be visible!)
---
Basically, we were using values of type `gexpr box = naked_gexpr marked box`
throughout when (re-)building expressions. This was done 99% of the time by
using `Bindlib.box_apply add_mark naked_e` right after building `naked_e`. In
lots of places, we needed to recover the annotation of this expression later on,
typically to build its parent term (to inherit the position, or build the type).
Since it wasn't always possible to wrap these uses within `box_apply` (esp. as
bindlib boxes aren't a monad), here and there we had to call `Bindlib.unbox`,
just to recover the position or type. This had the very unpleasant effect of
forcing the resolution of the whole box (including applying any stored closures)
to reach the top-level annotation which isn't even dependant on specific
variable bindings. Then, generally, throwing away the result.
Therefore, the change proposed here transforms
- `naked_gexpr marked Bindlib.box` into
- `naked_gexpr Bindlib.box marked` (aliased to `boxed_gexpr` or `gexpr boxed` for
convenience)
This means only
1. not fitting the mark into the box right away when building, and
2. accessing the top-level mark directly without unboxing
The functions for building terms from module `Shared_ast.Expr` could be changed
easily. But then they needed to be consistently used throughout, without
manually building terms through `Bindlib.apply_box` -- which covers most of the
changes in this patch.
`Expr.Box.inj` is provided to swap back to a box, before binding for example.
Additionally, this gives a 40% speedup on `make -C examples pass_all_tests`,
which hints at the amount of unnecessary work we were doing --'
2022-10-06 20:13:45 +03:00
|
|
|
|
2022-11-17 19:13:35 +03:00
|
|
|
let eabs binder tys mark =
|
|
|
|
Bindlib.box_apply (fun binder -> EAbs { binder; tys }) binder, mark
|
2022-07-28 11:36:36 +03:00
|
|
|
|
2022-11-17 19:13:35 +03:00
|
|
|
let eapp f args = Box.app1n f args @@ fun f args -> EApp { f; args }
|
Swap boxing and annotations in expressions
This was the only reasonable solution I found to the issue raised
[here](https://github.com/CatalaLang/catala/pull/334#discussion_r987175884).
This was a pretty tedious rewrite, but it should now ensure we are doing things
correctly. As a bonus, the "smart" expression constructors are now used
everywhere to build expressions (so another refactoring like this one should be
much easier) and this makes the code overall feel more
straightforward (`Bindlib.box_apply` or `let+` no longer need to be visible!)
---
Basically, we were using values of type `gexpr box = naked_gexpr marked box`
throughout when (re-)building expressions. This was done 99% of the time by
using `Bindlib.box_apply add_mark naked_e` right after building `naked_e`. In
lots of places, we needed to recover the annotation of this expression later on,
typically to build its parent term (to inherit the position, or build the type).
Since it wasn't always possible to wrap these uses within `box_apply` (esp. as
bindlib boxes aren't a monad), here and there we had to call `Bindlib.unbox`,
just to recover the position or type. This had the very unpleasant effect of
forcing the resolution of the whole box (including applying any stored closures)
to reach the top-level annotation which isn't even dependant on specific
variable bindings. Then, generally, throwing away the result.
Therefore, the change proposed here transforms
- `naked_gexpr marked Bindlib.box` into
- `naked_gexpr Bindlib.box marked` (aliased to `boxed_gexpr` or `gexpr boxed` for
convenience)
This means only
1. not fitting the mark into the box right away when building, and
2. accessing the top-level mark directly without unboxing
The functions for building terms from module `Shared_ast.Expr` could be changed
easily. But then they needed to be consistently used throughout, without
manually building terms through `Bindlib.apply_box` -- which covers most of the
changes in this patch.
`Expr.Box.inj` is provided to swap back to a box, before binding for example.
Additionally, this gives a 40% speedup on `make -C examples pass_all_tests`,
which hints at the amount of unnecessary work we were doing --'
2022-10-06 20:13:45 +03:00
|
|
|
let eassert e1 = Box.app1 e1 @@ fun e1 -> EAssert e1
|
Add overloaded operators for the common operations
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`.
2022-11-29 11:47:53 +03:00
|
|
|
let eop op tys = Box.app0 @@ EOp { op; tys }
|
2022-07-28 11:36:36 +03:00
|
|
|
|
Swap boxing and annotations in expressions
This was the only reasonable solution I found to the issue raised
[here](https://github.com/CatalaLang/catala/pull/334#discussion_r987175884).
This was a pretty tedious rewrite, but it should now ensure we are doing things
correctly. As a bonus, the "smart" expression constructors are now used
everywhere to build expressions (so another refactoring like this one should be
much easier) and this makes the code overall feel more
straightforward (`Bindlib.box_apply` or `let+` no longer need to be visible!)
---
Basically, we were using values of type `gexpr box = naked_gexpr marked box`
throughout when (re-)building expressions. This was done 99% of the time by
using `Bindlib.box_apply add_mark naked_e` right after building `naked_e`. In
lots of places, we needed to recover the annotation of this expression later on,
typically to build its parent term (to inherit the position, or build the type).
Since it wasn't always possible to wrap these uses within `box_apply` (esp. as
bindlib boxes aren't a monad), here and there we had to call `Bindlib.unbox`,
just to recover the position or type. This had the very unpleasant effect of
forcing the resolution of the whole box (including applying any stored closures)
to reach the top-level annotation which isn't even dependant on specific
variable bindings. Then, generally, throwing away the result.
Therefore, the change proposed here transforms
- `naked_gexpr marked Bindlib.box` into
- `naked_gexpr Bindlib.box marked` (aliased to `boxed_gexpr` or `gexpr boxed` for
convenience)
This means only
1. not fitting the mark into the box right away when building, and
2. accessing the top-level mark directly without unboxing
The functions for building terms from module `Shared_ast.Expr` could be changed
easily. But then they needed to be consistently used throughout, without
manually building terms through `Bindlib.apply_box` -- which covers most of the
changes in this patch.
`Expr.Box.inj` is provided to swap back to a box, before binding for example.
Additionally, this gives a 40% speedup on `make -C examples pass_all_tests`,
which hints at the amount of unnecessary work we were doing --'
2022-10-06 20:13:45 +03:00
|
|
|
let edefault excepts just cons =
|
|
|
|
Box.app2n just cons excepts
|
2022-11-17 19:13:35 +03:00
|
|
|
@@ fun just cons excepts -> EDefault { excepts; just; cons }
|
2022-07-28 11:36:36 +03:00
|
|
|
|
2022-11-17 19:13:35 +03:00
|
|
|
let eifthenelse cond etrue efalse =
|
|
|
|
Box.app3 cond etrue efalse
|
|
|
|
@@ fun cond etrue efalse -> EIfThenElse { cond; etrue; efalse }
|
2022-08-17 19:14:30 +03:00
|
|
|
|
2022-11-17 19:13:35 +03:00
|
|
|
let eerroronempty e1 = Box.app1 e1 @@ fun e1 -> EErrorOnEmpty e1
|
2023-05-17 16:44:57 +03:00
|
|
|
let eemptyerror mark = Mark.add mark (Bindlib.box EEmptyError)
|
Swap boxing and annotations in expressions
This was the only reasonable solution I found to the issue raised
[here](https://github.com/CatalaLang/catala/pull/334#discussion_r987175884).
This was a pretty tedious rewrite, but it should now ensure we are doing things
correctly. As a bonus, the "smart" expression constructors are now used
everywhere to build expressions (so another refactoring like this one should be
much easier) and this makes the code overall feel more
straightforward (`Bindlib.box_apply` or `let+` no longer need to be visible!)
---
Basically, we were using values of type `gexpr box = naked_gexpr marked box`
throughout when (re-)building expressions. This was done 99% of the time by
using `Bindlib.box_apply add_mark naked_e` right after building `naked_e`. In
lots of places, we needed to recover the annotation of this expression later on,
typically to build its parent term (to inherit the position, or build the type).
Since it wasn't always possible to wrap these uses within `box_apply` (esp. as
bindlib boxes aren't a monad), here and there we had to call `Bindlib.unbox`,
just to recover the position or type. This had the very unpleasant effect of
forcing the resolution of the whole box (including applying any stored closures)
to reach the top-level annotation which isn't even dependant on specific
variable bindings. Then, generally, throwing away the result.
Therefore, the change proposed here transforms
- `naked_gexpr marked Bindlib.box` into
- `naked_gexpr Bindlib.box marked` (aliased to `boxed_gexpr` or `gexpr boxed` for
convenience)
This means only
1. not fitting the mark into the box right away when building, and
2. accessing the top-level mark directly without unboxing
The functions for building terms from module `Shared_ast.Expr` could be changed
easily. But then they needed to be consistently used throughout, without
manually building terms through `Bindlib.apply_box` -- which covers most of the
changes in this patch.
`Expr.Box.inj` is provided to swap back to a box, before binding for example.
Additionally, this gives a 40% speedup on `make -C examples pass_all_tests`,
which hints at the amount of unnecessary work we were doing --'
2022-10-06 20:13:45 +03:00
|
|
|
let eraise e1 = Box.app0 @@ ERaise e1
|
2022-11-17 19:13:35 +03:00
|
|
|
|
|
|
|
let ecatch body exn handler =
|
|
|
|
Box.app2 body handler @@ fun body handler -> ECatch { body; exn; handler }
|
|
|
|
|
2023-04-19 19:26:50 +03:00
|
|
|
let ecustom obj targs tret mark =
|
|
|
|
Mark.add mark (Bindlib.box (ECustom { obj; targs; tret }))
|
|
|
|
|
Swap boxing and annotations in expressions
This was the only reasonable solution I found to the issue raised
[here](https://github.com/CatalaLang/catala/pull/334#discussion_r987175884).
This was a pretty tedious rewrite, but it should now ensure we are doing things
correctly. As a bonus, the "smart" expression constructors are now used
everywhere to build expressions (so another refactoring like this one should be
much easier) and this makes the code overall feel more
straightforward (`Bindlib.box_apply` or `let+` no longer need to be visible!)
---
Basically, we were using values of type `gexpr box = naked_gexpr marked box`
throughout when (re-)building expressions. This was done 99% of the time by
using `Bindlib.box_apply add_mark naked_e` right after building `naked_e`. In
lots of places, we needed to recover the annotation of this expression later on,
typically to build its parent term (to inherit the position, or build the type).
Since it wasn't always possible to wrap these uses within `box_apply` (esp. as
bindlib boxes aren't a monad), here and there we had to call `Bindlib.unbox`,
just to recover the position or type. This had the very unpleasant effect of
forcing the resolution of the whole box (including applying any stored closures)
to reach the top-level annotation which isn't even dependant on specific
variable bindings. Then, generally, throwing away the result.
Therefore, the change proposed here transforms
- `naked_gexpr marked Bindlib.box` into
- `naked_gexpr Bindlib.box marked` (aliased to `boxed_gexpr` or `gexpr boxed` for
convenience)
This means only
1. not fitting the mark into the box right away when building, and
2. accessing the top-level mark directly without unboxing
The functions for building terms from module `Shared_ast.Expr` could be changed
easily. But then they needed to be consistently used throughout, without
manually building terms through `Bindlib.apply_box` -- which covers most of the
changes in this patch.
`Expr.Box.inj` is provided to swap back to a box, before binding for example.
Additionally, this gives a 40% speedup on `make -C examples pass_all_tests`,
which hints at the amount of unnecessary work we were doing --'
2022-10-06 20:13:45 +03:00
|
|
|
let elocation loc = Box.app0 @@ ELocation loc
|
2022-08-17 19:14:30 +03:00
|
|
|
|
2023-08-10 17:52:39 +03:00
|
|
|
let estruct ~name ~(fields : ('a, 't) boxed_gexpr StructField.Map.t) mark =
|
2023-05-17 16:44:57 +03:00
|
|
|
Mark.add mark
|
Swap boxing and annotations in expressions
This was the only reasonable solution I found to the issue raised
[here](https://github.com/CatalaLang/catala/pull/334#discussion_r987175884).
This was a pretty tedious rewrite, but it should now ensure we are doing things
correctly. As a bonus, the "smart" expression constructors are now used
everywhere to build expressions (so another refactoring like this one should be
much easier) and this makes the code overall feel more
straightforward (`Bindlib.box_apply` or `let+` no longer need to be visible!)
---
Basically, we were using values of type `gexpr box = naked_gexpr marked box`
throughout when (re-)building expressions. This was done 99% of the time by
using `Bindlib.box_apply add_mark naked_e` right after building `naked_e`. In
lots of places, we needed to recover the annotation of this expression later on,
typically to build its parent term (to inherit the position, or build the type).
Since it wasn't always possible to wrap these uses within `box_apply` (esp. as
bindlib boxes aren't a monad), here and there we had to call `Bindlib.unbox`,
just to recover the position or type. This had the very unpleasant effect of
forcing the resolution of the whole box (including applying any stored closures)
to reach the top-level annotation which isn't even dependant on specific
variable bindings. Then, generally, throwing away the result.
Therefore, the change proposed here transforms
- `naked_gexpr marked Bindlib.box` into
- `naked_gexpr Bindlib.box marked` (aliased to `boxed_gexpr` or `gexpr boxed` for
convenience)
This means only
1. not fitting the mark into the box right away when building, and
2. accessing the top-level mark directly without unboxing
The functions for building terms from module `Shared_ast.Expr` could be changed
easily. But then they needed to be consistently used throughout, without
manually building terms through `Bindlib.apply_box` -- which covers most of the
changes in this patch.
`Expr.Box.inj` is provided to swap back to a box, before binding for example.
Additionally, this gives a 40% speedup on `make -C examples pass_all_tests`,
which hints at the amount of unnecessary work we were doing --'
2022-10-06 20:13:45 +03:00
|
|
|
@@ Bindlib.box_apply
|
2022-11-17 19:13:35 +03:00
|
|
|
(fun fields -> EStruct { name; fields })
|
2022-11-21 12:12:45 +03:00
|
|
|
(Box.lift_struct (StructField.Map.map Box.lift fields))
|
2022-08-17 19:14:30 +03:00
|
|
|
|
2023-08-30 18:49:29 +03:00
|
|
|
let edstructaccess ~name_opt ~field ~e =
|
|
|
|
Box.app1 e @@ fun e -> EDStructAccess { name_opt; field; e }
|
2022-11-22 22:57:59 +03:00
|
|
|
|
2023-08-10 17:52:39 +03:00
|
|
|
let estructaccess ~name ~field ~e =
|
|
|
|
Box.app1 e @@ fun e -> EStructAccess { name; field; e }
|
2022-08-17 19:14:30 +03:00
|
|
|
|
2023-08-10 17:52:39 +03:00
|
|
|
let einj ~name ~cons ~e = Box.app1 e @@ fun e -> EInj { name; cons; e }
|
2022-08-17 19:14:30 +03:00
|
|
|
|
2023-08-10 17:52:39 +03:00
|
|
|
let ematch ~name ~e ~cases mark =
|
2023-05-17 16:44:57 +03:00
|
|
|
Mark.add mark
|
Swap boxing and annotations in expressions
This was the only reasonable solution I found to the issue raised
[here](https://github.com/CatalaLang/catala/pull/334#discussion_r987175884).
This was a pretty tedious rewrite, but it should now ensure we are doing things
correctly. As a bonus, the "smart" expression constructors are now used
everywhere to build expressions (so another refactoring like this one should be
much easier) and this makes the code overall feel more
straightforward (`Bindlib.box_apply` or `let+` no longer need to be visible!)
---
Basically, we were using values of type `gexpr box = naked_gexpr marked box`
throughout when (re-)building expressions. This was done 99% of the time by
using `Bindlib.box_apply add_mark naked_e` right after building `naked_e`. In
lots of places, we needed to recover the annotation of this expression later on,
typically to build its parent term (to inherit the position, or build the type).
Since it wasn't always possible to wrap these uses within `box_apply` (esp. as
bindlib boxes aren't a monad), here and there we had to call `Bindlib.unbox`,
just to recover the position or type. This had the very unpleasant effect of
forcing the resolution of the whole box (including applying any stored closures)
to reach the top-level annotation which isn't even dependant on specific
variable bindings. Then, generally, throwing away the result.
Therefore, the change proposed here transforms
- `naked_gexpr marked Bindlib.box` into
- `naked_gexpr Bindlib.box marked` (aliased to `boxed_gexpr` or `gexpr boxed` for
convenience)
This means only
1. not fitting the mark into the box right away when building, and
2. accessing the top-level mark directly without unboxing
The functions for building terms from module `Shared_ast.Expr` could be changed
easily. But then they needed to be consistently used throughout, without
manually building terms through `Bindlib.apply_box` -- which covers most of the
changes in this patch.
`Expr.Box.inj` is provided to swap back to a box, before binding for example.
Additionally, this gives a 40% speedup on `make -C examples pass_all_tests`,
which hints at the amount of unnecessary work we were doing --'
2022-10-06 20:13:45 +03:00
|
|
|
@@ Bindlib.box_apply2
|
2022-11-17 19:13:35 +03:00
|
|
|
(fun e cases -> EMatch { name; e; cases })
|
|
|
|
(Box.lift e)
|
2022-11-21 12:12:45 +03:00
|
|
|
(Box.lift_enum (EnumConstructor.Map.map Box.lift cases))
|
2022-07-28 11:36:36 +03:00
|
|
|
|
2023-08-30 18:49:29 +03:00
|
|
|
let escopecall ~scope ~args mark =
|
2023-05-17 16:44:57 +03:00
|
|
|
Mark.add mark
|
2022-10-21 16:47:17 +03:00
|
|
|
@@ Bindlib.box_apply
|
2023-08-30 18:49:29 +03:00
|
|
|
(fun args -> EScopeCall { scope; args })
|
2022-11-21 12:12:45 +03:00
|
|
|
(Box.lift_scope_vars (ScopeVar.Map.map Box.lift args))
|
2022-10-21 16:47:17 +03:00
|
|
|
|
2022-08-12 23:42:39 +03:00
|
|
|
(* - Manipulation of marks - *)
|
|
|
|
|
2022-08-22 19:53:30 +03:00
|
|
|
let no_mark : type m. m mark -> m mark = function
|
2022-08-12 23:42:39 +03:00
|
|
|
| Untyped _ -> Untyped { pos = Pos.no_pos }
|
2023-05-17 16:44:57 +03:00
|
|
|
| Typed _ -> Typed { pos = Pos.no_pos; ty = Mark.add Pos.no_pos TAny }
|
2023-05-17 17:15:00 +03:00
|
|
|
| Custom { custom; pos = _ } -> Custom { pos = Pos.no_pos; custom }
|
2022-08-12 23:42:39 +03:00
|
|
|
|
|
|
|
let mark_pos (type m) (m : m mark) : Pos.t =
|
2023-05-17 17:15:00 +03:00
|
|
|
match m with Untyped { pos } | Typed { pos; _ } | Custom { pos; _ } -> pos
|
2022-08-12 23:42:39 +03:00
|
|
|
|
2023-05-17 17:15:00 +03:00
|
|
|
let pos (type m) (x : ('a, m) marked) : Pos.t = mark_pos (Mark.get x)
|
2022-08-16 17:54:42 +03:00
|
|
|
|
2023-06-12 16:02:08 +03:00
|
|
|
let fun_id ?(var_name : string = "x") mark : ('a any, 'm) boxed_gexpr =
|
|
|
|
let x = Var.make var_name in
|
2023-03-10 17:33:58 +03:00
|
|
|
eabs (bind [| x |] (evar x mark)) [TAny, mark_pos mark] mark
|
|
|
|
|
2022-08-25 18:29:00 +03:00
|
|
|
let ty (_, m) : typ = match m with Typed { ty; _ } -> ty
|
2022-08-12 23:42:39 +03:00
|
|
|
|
2023-05-17 17:15:00 +03:00
|
|
|
let set_ty (type m) (ty : typ) (x : ('a, m) marked) : ('a, typed) marked =
|
2023-05-17 16:44:57 +03:00
|
|
|
Mark.add
|
|
|
|
(match Mark.get x with
|
2022-08-12 23:42:39 +03:00
|
|
|
| Untyped { pos } -> Typed { pos; ty }
|
2023-05-17 17:15:00 +03:00
|
|
|
| Typed m -> Typed { m with ty }
|
|
|
|
| Custom { pos; _ } -> Typed { pos; ty })
|
2023-05-17 16:44:57 +03:00
|
|
|
(Mark.remove x)
|
2022-08-12 23:42:39 +03:00
|
|
|
|
2022-08-25 20:46:13 +03:00
|
|
|
let map_mark (type m) (pos_f : Pos.t -> Pos.t) (ty_f : typ -> typ) (m : m mark)
|
|
|
|
: m mark =
|
2022-08-12 23:42:39 +03:00
|
|
|
match m with
|
|
|
|
| Untyped { pos } -> Untyped { pos = pos_f pos }
|
|
|
|
| Typed { pos; ty } -> Typed { pos = pos_f pos; ty = ty_f ty }
|
2023-05-17 17:15:00 +03:00
|
|
|
| Custom { pos; custom } -> Custom { pos = pos_f pos; custom }
|
2022-08-12 23:42:39 +03:00
|
|
|
|
|
|
|
let map_mark2
|
|
|
|
(type m)
|
|
|
|
(pos_f : Pos.t -> Pos.t -> Pos.t)
|
2022-08-25 18:29:00 +03:00
|
|
|
(ty_f : typed -> typed -> typ)
|
2022-08-12 23:42:39 +03:00
|
|
|
(m1 : m mark)
|
|
|
|
(m2 : m mark) : m mark =
|
|
|
|
match m1, m2 with
|
|
|
|
| Untyped m1, Untyped m2 -> Untyped { pos = pos_f m1.pos m2.pos }
|
|
|
|
| Typed m1, Typed m2 -> Typed { pos = pos_f m1.pos m2.pos; ty = ty_f m1 m2 }
|
2023-05-17 17:15:00 +03:00
|
|
|
| Custom _, Custom _ -> invalid_arg "map_mark2"
|
2022-08-12 23:42:39 +03:00
|
|
|
|
|
|
|
let fold_marks
|
|
|
|
(type m)
|
|
|
|
(pos_f : Pos.t list -> Pos.t)
|
2022-08-25 18:29:00 +03:00
|
|
|
(ty_f : typed list -> typ)
|
2022-08-12 23:42:39 +03:00
|
|
|
(ms : m mark list) : m mark =
|
|
|
|
match ms with
|
|
|
|
| [] -> invalid_arg "Dcalc.Ast.fold_mark"
|
|
|
|
| Untyped _ :: _ as ms ->
|
|
|
|
Untyped { pos = pos_f (List.map (function Untyped { pos } -> pos) ms) }
|
2023-01-12 17:12:11 +03:00
|
|
|
| Typed _ :: _ as ms ->
|
2022-08-12 23:42:39 +03:00
|
|
|
Typed
|
|
|
|
{
|
|
|
|
pos = pos_f (List.map (function Typed { pos; _ } -> pos) ms);
|
|
|
|
ty = ty_f (List.map (function Typed m -> m) ms);
|
|
|
|
}
|
2023-05-17 17:15:00 +03:00
|
|
|
| Custom _ :: _ -> invalid_arg "map_mark2"
|
2022-08-12 23:42:39 +03:00
|
|
|
|
2022-09-30 17:52:35 +03:00
|
|
|
let with_pos (type m) (pos : Pos.t) (m : m mark) : m mark =
|
|
|
|
map_mark (fun _ -> pos) (fun ty -> ty) m
|
|
|
|
|
2022-09-12 18:03:44 +03:00
|
|
|
let map_ty (type m) (ty_f : typ -> typ) (m : m mark) : m mark =
|
|
|
|
map_mark (fun pos -> pos) ty_f m
|
|
|
|
|
|
|
|
let with_ty (type m) (m : m mark) ?pos (ty : typ) : m mark =
|
|
|
|
map_mark (fun default -> Option.value pos ~default) (fun _ -> ty) m
|
|
|
|
|
|
|
|
let maybe_ty (type m) ?(typ = TAny) (m : m mark) : typ =
|
2023-05-17 17:15:00 +03:00
|
|
|
match m with
|
|
|
|
| Untyped { pos } | Custom { pos; _ } -> Mark.add pos typ
|
|
|
|
| Typed { ty; _ } -> ty
|
2022-09-12 18:03:44 +03:00
|
|
|
|
2023-05-17 14:26:47 +03:00
|
|
|
(* - Predefined types (option) - *)
|
|
|
|
|
2023-08-30 18:49:29 +03:00
|
|
|
let option_enum = EnumName.fresh [] ("eoption", Pos.no_pos)
|
2023-05-17 14:26:47 +03:00
|
|
|
let none_constr = EnumConstructor.fresh ("ENone", Pos.no_pos)
|
|
|
|
let some_constr = EnumConstructor.fresh ("ESome", Pos.no_pos)
|
|
|
|
|
|
|
|
let option_enum_config =
|
|
|
|
EnumConstructor.Map.singleton none_constr (TLit TUnit, Pos.no_pos)
|
|
|
|
|> EnumConstructor.Map.add some_constr (TAny, Pos.no_pos)
|
|
|
|
|
2022-08-12 23:42:39 +03:00
|
|
|
(* - Traversal functions - *)
|
2022-07-28 11:36:36 +03:00
|
|
|
|
2022-08-17 19:14:30 +03:00
|
|
|
(* shallow map *)
|
2023-04-05 11:23:21 +03:00
|
|
|
let map
|
2023-03-30 19:57:51 +03:00
|
|
|
(type a b)
|
|
|
|
~(f : (a, 'm1) gexpr -> (b, 'm2) boxed_gexpr)
|
2023-05-17 17:15:00 +03:00
|
|
|
(e : ((a, b, 'm1) base_gexpr, 'm2) marked) : (b, 'm2) boxed_gexpr =
|
2023-05-17 16:44:57 +03:00
|
|
|
let m = Mark.get e in
|
|
|
|
match Mark.remove e with
|
2022-07-28 11:36:36 +03:00
|
|
|
| ELit l -> elit l m
|
2022-11-17 19:13:35 +03:00
|
|
|
| EApp { f = e1; args } -> eapp (f e1) (List.map f args) m
|
2023-04-05 11:23:21 +03:00
|
|
|
| EOp { op; tys } -> eop op tys m
|
2022-11-17 19:13:35 +03:00
|
|
|
| EArray args -> earray (List.map f args) m
|
2022-08-12 23:42:39 +03:00
|
|
|
| EVar v -> evar (Var.translate v) m
|
2023-08-30 18:49:29 +03:00
|
|
|
| EExternal { name } -> eexternal ~name m
|
2022-11-17 19:13:35 +03:00
|
|
|
| EAbs { binder; tys } ->
|
2022-07-28 11:36:36 +03:00
|
|
|
let vars, body = Bindlib.unmbind binder in
|
2022-11-17 19:13:35 +03:00
|
|
|
let body = f body in
|
Swap boxing and annotations in expressions
This was the only reasonable solution I found to the issue raised
[here](https://github.com/CatalaLang/catala/pull/334#discussion_r987175884).
This was a pretty tedious rewrite, but it should now ensure we are doing things
correctly. As a bonus, the "smart" expression constructors are now used
everywhere to build expressions (so another refactoring like this one should be
much easier) and this makes the code overall feel more
straightforward (`Bindlib.box_apply` or `let+` no longer need to be visible!)
---
Basically, we were using values of type `gexpr box = naked_gexpr marked box`
throughout when (re-)building expressions. This was done 99% of the time by
using `Bindlib.box_apply add_mark naked_e` right after building `naked_e`. In
lots of places, we needed to recover the annotation of this expression later on,
typically to build its parent term (to inherit the position, or build the type).
Since it wasn't always possible to wrap these uses within `box_apply` (esp. as
bindlib boxes aren't a monad), here and there we had to call `Bindlib.unbox`,
just to recover the position or type. This had the very unpleasant effect of
forcing the resolution of the whole box (including applying any stored closures)
to reach the top-level annotation which isn't even dependant on specific
variable bindings. Then, generally, throwing away the result.
Therefore, the change proposed here transforms
- `naked_gexpr marked Bindlib.box` into
- `naked_gexpr Bindlib.box marked` (aliased to `boxed_gexpr` or `gexpr boxed` for
convenience)
This means only
1. not fitting the mark into the box right away when building, and
2. accessing the top-level mark directly without unboxing
The functions for building terms from module `Shared_ast.Expr` could be changed
easily. But then they needed to be consistently used throughout, without
manually building terms through `Bindlib.apply_box` -- which covers most of the
changes in this patch.
`Expr.Box.inj` is provided to swap back to a box, before binding for example.
Additionally, this gives a 40% speedup on `make -C examples pass_all_tests`,
which hints at the amount of unnecessary work we were doing --'
2022-10-06 20:13:45 +03:00
|
|
|
let binder = bind (Array.map Var.translate vars) body in
|
2022-11-17 19:13:35 +03:00
|
|
|
eabs binder tys m
|
|
|
|
| EIfThenElse { cond; etrue; efalse } ->
|
|
|
|
eifthenelse (f cond) (f etrue) (f efalse) m
|
|
|
|
| ETuple args -> etuple (List.map f args) m
|
|
|
|
| ETupleAccess { e; index; size } -> etupleaccess (f e) index size m
|
2023-08-10 17:52:39 +03:00
|
|
|
| EInj { name; cons; e } -> einj ~name ~cons ~e:(f e) m
|
2022-11-17 19:13:35 +03:00
|
|
|
| EAssert e1 -> eassert (f e1) m
|
|
|
|
| EDefault { excepts; just; cons } ->
|
|
|
|
edefault (List.map f excepts) (f just) (f cons) m
|
2023-03-30 19:53:07 +03:00
|
|
|
| EEmptyError -> eemptyerror m
|
2022-11-17 19:13:35 +03:00
|
|
|
| EErrorOnEmpty e1 -> eerroronempty (f e1) m
|
|
|
|
| ECatch { body; exn; handler } -> ecatch (f body) exn (f handler) m
|
2022-08-17 19:14:30 +03:00
|
|
|
| ERaise exn -> eraise exn m
|
2023-04-05 11:23:21 +03:00
|
|
|
| ELocation loc -> elocation loc m
|
2022-11-17 19:13:35 +03:00
|
|
|
| EStruct { name; fields } ->
|
2022-11-21 12:12:45 +03:00
|
|
|
let fields = StructField.Map.map f fields in
|
2023-08-10 17:52:39 +03:00
|
|
|
estruct ~name ~fields m
|
2023-08-30 18:49:29 +03:00
|
|
|
| EDStructAccess { name_opt; field; e } ->
|
|
|
|
edstructaccess ~name_opt ~field ~e:(f e) m
|
2023-08-16 01:04:45 +03:00
|
|
|
| EStructAccess { name; field; e } -> estructaccess ~name ~field ~e:(f e) m
|
2023-08-10 17:52:39 +03:00
|
|
|
| EMatch { name; e; cases } ->
|
2022-11-21 12:12:45 +03:00
|
|
|
let cases = EnumConstructor.Map.map f cases in
|
2023-08-10 17:52:39 +03:00
|
|
|
ematch ~name ~e:(f e) ~cases m
|
2023-08-30 18:49:29 +03:00
|
|
|
| EScopeCall { scope; args } ->
|
2023-08-10 17:52:39 +03:00
|
|
|
let args = ScopeVar.Map.map f args in
|
2023-08-30 18:49:29 +03:00
|
|
|
escopecall ~scope ~args m
|
2023-04-19 19:26:50 +03:00
|
|
|
| ECustom { obj; targs; tret } -> ecustom obj targs tret m
|
2022-07-28 11:36:36 +03:00
|
|
|
|
2022-11-17 19:13:35 +03:00
|
|
|
let rec map_top_down ~f e = map ~f:(map_top_down ~f) (f e)
|
2023-05-17 17:15:00 +03:00
|
|
|
let map_marks ~f e = map_top_down ~f:(Mark.map_mark f) e
|
2022-07-28 11:36:36 +03:00
|
|
|
|
2023-04-04 12:10:59 +03:00
|
|
|
(* Folds the given function on the direct children of the given expression. *)
|
2022-10-10 16:15:36 +03:00
|
|
|
let shallow_fold
|
|
|
|
(type a)
|
|
|
|
(f : (a, 'm) gexpr -> 'acc -> 'acc)
|
|
|
|
(e : (a, 'm) gexpr)
|
|
|
|
(acc : 'acc) : 'acc =
|
|
|
|
let lfold x acc = List.fold_left (fun acc x -> f x acc) acc x in
|
2023-05-17 16:44:57 +03:00
|
|
|
match Mark.remove e with
|
2023-04-19 19:26:50 +03:00
|
|
|
| ELit _ | EOp _ | EVar _ | EExternal _ | ERaise _ | ELocation _ | EEmptyError
|
|
|
|
->
|
|
|
|
acc
|
2022-11-17 19:13:35 +03:00
|
|
|
| EApp { f = e; args } -> acc |> f e |> lfold args
|
2022-10-10 16:15:36 +03:00
|
|
|
| EArray args -> acc |> lfold args
|
2023-04-03 14:42:14 +03:00
|
|
|
| EAbs { binder; tys = _ } ->
|
|
|
|
let _, body = Bindlib.unmbind binder in
|
|
|
|
acc |> f body
|
2022-11-17 19:13:35 +03:00
|
|
|
| EIfThenElse { cond; etrue; efalse } -> acc |> f cond |> f etrue |> f efalse
|
|
|
|
| ETuple args -> acc |> lfold args
|
|
|
|
| ETupleAccess { e; _ } -> acc |> f e
|
|
|
|
| EInj { e; _ } -> acc |> f e
|
|
|
|
| EAssert e -> acc |> f e
|
|
|
|
| EDefault { excepts; just; cons } -> acc |> lfold excepts |> f just |> f cons
|
|
|
|
| EErrorOnEmpty e -> acc |> f e
|
|
|
|
| ECatch { body; handler; _ } -> acc |> f body |> f handler
|
2022-11-21 12:12:45 +03:00
|
|
|
| EStruct { fields; _ } -> acc |> StructField.Map.fold (fun _ -> f) fields
|
2022-11-22 22:57:59 +03:00
|
|
|
| EDStructAccess { e; _ } -> acc |> f e
|
2022-11-17 19:13:35 +03:00
|
|
|
| EStructAccess { e; _ } -> acc |> f e
|
|
|
|
| EMatch { e; cases; _ } ->
|
2022-11-21 12:12:45 +03:00
|
|
|
acc |> f e |> EnumConstructor.Map.fold (fun _ -> f) cases
|
|
|
|
| EScopeCall { args; _ } -> acc |> ScopeVar.Map.fold (fun _ -> f) args
|
2023-04-19 19:26:50 +03:00
|
|
|
| ECustom _ -> acc
|
2022-11-17 19:13:35 +03:00
|
|
|
|
|
|
|
(* Like [map], but also allows to gather a result bottom-up. *)
|
|
|
|
let map_gather
|
|
|
|
(type a)
|
|
|
|
~(acc : 'acc)
|
|
|
|
~(join : 'acc -> 'acc -> 'acc)
|
|
|
|
~(f : (a, 'm1) gexpr -> 'acc * (a, 'm2) boxed_gexpr)
|
2023-05-17 17:15:00 +03:00
|
|
|
(e : ((a, 'm1) naked_gexpr, 'm2) marked) : 'acc * (a, 'm2) boxed_gexpr =
|
2023-05-17 16:44:57 +03:00
|
|
|
let m = Mark.get e in
|
2022-11-17 19:13:35 +03:00
|
|
|
let lfoldmap es =
|
|
|
|
let acc, r_es =
|
|
|
|
List.fold_left
|
|
|
|
(fun (acc, es) e ->
|
|
|
|
let acc1, e = f e in
|
|
|
|
join acc acc1, e :: es)
|
|
|
|
(acc, []) es
|
|
|
|
in
|
|
|
|
acc, List.rev r_es
|
|
|
|
in
|
2023-05-17 16:44:57 +03:00
|
|
|
match Mark.remove e with
|
2022-11-17 19:13:35 +03:00
|
|
|
| ELit l -> acc, elit l m
|
|
|
|
| EApp { f = e1; args } ->
|
|
|
|
let acc1, f = f e1 in
|
|
|
|
let acc2, args = lfoldmap args in
|
|
|
|
join acc1 acc2, eapp f args m
|
Add overloaded operators for the common operations
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`.
2022-11-29 11:47:53 +03:00
|
|
|
| EOp { op; tys } -> acc, eop op tys m
|
2022-11-17 19:13:35 +03:00
|
|
|
| EArray args ->
|
|
|
|
let acc, args = lfoldmap args in
|
|
|
|
acc, earray args m
|
|
|
|
| EVar v -> acc, evar (Var.translate v) m
|
2023-08-30 18:49:29 +03:00
|
|
|
| EExternal { name } -> acc, eexternal ~name m
|
2022-11-17 19:13:35 +03:00
|
|
|
| EAbs { binder; tys } ->
|
|
|
|
let vars, body = Bindlib.unmbind binder in
|
|
|
|
let acc, body = f body in
|
|
|
|
let binder = bind (Array.map Var.translate vars) body in
|
|
|
|
acc, eabs binder tys m
|
|
|
|
| EIfThenElse { cond; etrue; efalse } ->
|
|
|
|
let acc1, cond = f cond in
|
|
|
|
let acc2, etrue = f etrue in
|
|
|
|
let acc3, efalse = f efalse in
|
|
|
|
join (join acc1 acc2) acc3, eifthenelse cond etrue efalse m
|
|
|
|
| ETuple args ->
|
|
|
|
let acc, args = lfoldmap args in
|
|
|
|
acc, etuple args m
|
|
|
|
| ETupleAccess { e; index; size } ->
|
|
|
|
let acc, e = f e in
|
|
|
|
acc, etupleaccess e index size m
|
2023-08-10 17:52:39 +03:00
|
|
|
| EInj { name; cons; e } ->
|
2022-11-17 19:13:35 +03:00
|
|
|
let acc, e = f e in
|
2023-08-16 01:04:45 +03:00
|
|
|
acc, einj ~name ~cons ~e m
|
2022-11-17 19:13:35 +03:00
|
|
|
| EAssert e ->
|
|
|
|
let acc, e = f e in
|
|
|
|
acc, eassert e m
|
|
|
|
| EDefault { excepts; just; cons } ->
|
|
|
|
let acc1, excepts = lfoldmap excepts in
|
|
|
|
let acc2, just = f just in
|
|
|
|
let acc3, cons = f cons in
|
|
|
|
join (join acc1 acc2) acc3, edefault excepts just cons m
|
2023-03-30 19:53:07 +03:00
|
|
|
| EEmptyError -> acc, eemptyerror m
|
2022-11-17 19:13:35 +03:00
|
|
|
| EErrorOnEmpty e ->
|
|
|
|
let acc, e = f e in
|
|
|
|
acc, eerroronempty e m
|
|
|
|
| ECatch { body; exn; handler } ->
|
|
|
|
let acc1, body = f body in
|
|
|
|
let acc2, handler = f handler in
|
|
|
|
join acc1 acc2, ecatch body exn handler m
|
|
|
|
| ERaise exn -> acc, eraise exn m
|
|
|
|
| ELocation loc -> acc, elocation loc m
|
|
|
|
| EStruct { name; fields } ->
|
|
|
|
let acc, fields =
|
2022-11-21 12:12:45 +03:00
|
|
|
StructField.Map.fold
|
2022-11-17 19:13:35 +03:00
|
|
|
(fun cons e (acc, fields) ->
|
|
|
|
let acc1, e = f e in
|
2022-11-21 12:12:45 +03:00
|
|
|
join acc acc1, StructField.Map.add cons e fields)
|
2022-11-17 19:13:35 +03:00
|
|
|
fields
|
2022-11-21 12:12:45 +03:00
|
|
|
(acc, StructField.Map.empty)
|
2022-11-17 19:13:35 +03:00
|
|
|
in
|
2023-08-10 17:52:39 +03:00
|
|
|
acc, estruct ~name ~fields m
|
2023-08-30 18:49:29 +03:00
|
|
|
| EDStructAccess { name_opt; field; e } ->
|
2022-11-22 22:57:59 +03:00
|
|
|
let acc, e = f e in
|
2023-08-30 18:49:29 +03:00
|
|
|
acc, edstructaccess ~name_opt ~field ~e m
|
2023-08-10 17:52:39 +03:00
|
|
|
| EStructAccess { name; field; e } ->
|
2022-11-17 19:13:35 +03:00
|
|
|
let acc, e = f e in
|
2023-08-10 17:52:39 +03:00
|
|
|
acc, estructaccess ~name ~field ~e m
|
|
|
|
| EMatch { name; e; cases } ->
|
2022-11-17 19:13:35 +03:00
|
|
|
let acc, e = f e in
|
|
|
|
let acc, cases =
|
2022-11-21 12:12:45 +03:00
|
|
|
EnumConstructor.Map.fold
|
2022-11-17 19:13:35 +03:00
|
|
|
(fun cons e (acc, cases) ->
|
|
|
|
let acc1, e = f e in
|
2022-11-21 12:12:45 +03:00
|
|
|
join acc acc1, EnumConstructor.Map.add cons e cases)
|
2022-11-17 19:13:35 +03:00
|
|
|
cases
|
2022-11-21 12:12:45 +03:00
|
|
|
(acc, EnumConstructor.Map.empty)
|
2022-11-17 19:13:35 +03:00
|
|
|
in
|
2023-08-10 17:52:39 +03:00
|
|
|
acc, ematch ~name ~e ~cases m
|
2023-08-30 18:49:29 +03:00
|
|
|
| EScopeCall { scope; args } ->
|
2022-11-17 19:13:35 +03:00
|
|
|
let acc, args =
|
2022-11-21 12:12:45 +03:00
|
|
|
ScopeVar.Map.fold
|
2022-11-17 19:13:35 +03:00
|
|
|
(fun var e (acc, args) ->
|
|
|
|
let acc1, e = f e in
|
2022-11-21 12:12:45 +03:00
|
|
|
join acc acc1, ScopeVar.Map.add var e args)
|
|
|
|
args (acc, ScopeVar.Map.empty)
|
2022-11-17 19:13:35 +03:00
|
|
|
in
|
2023-08-30 18:49:29 +03:00
|
|
|
acc, escopecall ~scope ~args m
|
2023-04-19 19:26:50 +03:00
|
|
|
| ECustom { obj; targs; tret } -> acc, ecustom obj targs tret m
|
2022-10-10 16:15:36 +03:00
|
|
|
|
2022-08-12 23:42:39 +03:00
|
|
|
(* - *)
|
|
|
|
|
|
|
|
(** See [Bindlib.box_term] documentation for why we are doing that. *)
|
2023-03-30 16:30:08 +03:00
|
|
|
let rec rebox (e : ('a any, 't) gexpr) = map ~f:rebox e
|
2022-08-12 23:42:39 +03:00
|
|
|
|
2023-05-17 16:44:57 +03:00
|
|
|
let box e = Mark.map Bindlib.box e
|
Swap boxing and annotations in expressions
This was the only reasonable solution I found to the issue raised
[here](https://github.com/CatalaLang/catala/pull/334#discussion_r987175884).
This was a pretty tedious rewrite, but it should now ensure we are doing things
correctly. As a bonus, the "smart" expression constructors are now used
everywhere to build expressions (so another refactoring like this one should be
much easier) and this makes the code overall feel more
straightforward (`Bindlib.box_apply` or `let+` no longer need to be visible!)
---
Basically, we were using values of type `gexpr box = naked_gexpr marked box`
throughout when (re-)building expressions. This was done 99% of the time by
using `Bindlib.box_apply add_mark naked_e` right after building `naked_e`. In
lots of places, we needed to recover the annotation of this expression later on,
typically to build its parent term (to inherit the position, or build the type).
Since it wasn't always possible to wrap these uses within `box_apply` (esp. as
bindlib boxes aren't a monad), here and there we had to call `Bindlib.unbox`,
just to recover the position or type. This had the very unpleasant effect of
forcing the resolution of the whole box (including applying any stored closures)
to reach the top-level annotation which isn't even dependant on specific
variable bindings. Then, generally, throwing away the result.
Therefore, the change proposed here transforms
- `naked_gexpr marked Bindlib.box` into
- `naked_gexpr Bindlib.box marked` (aliased to `boxed_gexpr` or `gexpr boxed` for
convenience)
This means only
1. not fitting the mark into the box right away when building, and
2. accessing the top-level mark directly without unboxing
The functions for building terms from module `Shared_ast.Expr` could be changed
easily. But then they needed to be consistently used throughout, without
manually building terms through `Bindlib.apply_box` -- which covers most of the
changes in this patch.
`Expr.Box.inj` is provided to swap back to a box, before binding for example.
Additionally, this gives a 40% speedup on `make -C examples pass_all_tests`,
which hints at the amount of unnecessary work we were doing --'
2022-10-06 20:13:45 +03:00
|
|
|
let unbox (e, m) = Bindlib.unbox e, m
|
2023-06-19 17:36:09 +03:00
|
|
|
|
|
|
|
let unbox_closed e =
|
|
|
|
Box.assert_closed (fst e);
|
|
|
|
unbox e
|
|
|
|
|
2022-08-12 23:42:39 +03:00
|
|
|
let untype e = map_marks ~f:(fun m -> Untyped { pos = mark_pos m }) e
|
2022-08-17 12:49:16 +03:00
|
|
|
|
|
|
|
(* Tests *)
|
|
|
|
|
2022-08-25 20:46:13 +03:00
|
|
|
let is_value (type a) (e : (a, _) gexpr) =
|
2023-05-17 16:44:57 +03:00
|
|
|
match Mark.remove e with
|
2022-08-17 12:49:16 +03:00
|
|
|
| ELit _ | EAbs _ | EOp _ | ERaise _ -> true
|
|
|
|
| _ -> false
|
|
|
|
|
2023-03-30 19:53:07 +03:00
|
|
|
let equal_lit (l1 : lit) (l2 : lit) =
|
Add overloaded operators for the common operations
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`.
2022-11-29 11:47:53 +03:00
|
|
|
let open Runtime.Oper in
|
2022-08-25 13:09:51 +03:00
|
|
|
match l1, l2 with
|
Add overloaded operators for the common operations
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`.
2022-11-29 11:47:53 +03:00
|
|
|
| LBool b1, LBool b2 -> not (o_xor b1 b2)
|
|
|
|
| LInt n1, LInt n2 -> o_eq_int_int n1 n2
|
|
|
|
| LRat r1, LRat r2 -> o_eq_rat_rat r1 r2
|
|
|
|
| LMoney m1, LMoney m2 -> o_eq_mon_mon m1 m2
|
2022-08-25 13:09:51 +03:00
|
|
|
| LUnit, LUnit -> true
|
Add overloaded operators for the common operations
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`.
2022-11-29 11:47:53 +03:00
|
|
|
| LDate d1, LDate d2 -> o_eq_dat_dat d1 d2
|
|
|
|
| LDuration d1, LDuration d2 -> o_eq_dur_dur d1 d2
|
2023-03-30 19:53:07 +03:00
|
|
|
| (LBool _ | LInt _ | LRat _ | LMoney _ | LUnit | LDate _ | LDuration _), _ ->
|
2022-08-25 13:09:51 +03:00
|
|
|
false
|
|
|
|
|
2023-03-30 19:53:07 +03:00
|
|
|
let compare_lit (l1 : lit) (l2 : lit) =
|
Add overloaded operators for the common operations
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`.
2022-11-29 11:47:53 +03:00
|
|
|
let open Runtime.Oper in
|
2022-08-25 13:09:51 +03:00
|
|
|
match l1, l2 with
|
|
|
|
| LBool b1, LBool b2 -> Bool.compare b1 b2
|
|
|
|
| LInt n1, LInt n2 ->
|
Add overloaded operators for the common operations
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`.
2022-11-29 11:47:53 +03:00
|
|
|
if o_lt_int_int n1 n2 then -1 else if o_eq_int_int n1 n2 then 0 else 1
|
2022-08-25 13:09:51 +03:00
|
|
|
| LRat r1, LRat r2 ->
|
Add overloaded operators for the common operations
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`.
2022-11-29 11:47:53 +03:00
|
|
|
if o_lt_rat_rat r1 r2 then -1 else if o_eq_rat_rat r1 r2 then 0 else 1
|
2022-08-25 13:09:51 +03:00
|
|
|
| LMoney m1, LMoney m2 ->
|
Add overloaded operators for the common operations
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`.
2022-11-29 11:47:53 +03:00
|
|
|
if o_lt_mon_mon m1 m2 then -1 else if o_eq_mon_mon m1 m2 then 0 else 1
|
2022-08-25 13:09:51 +03:00
|
|
|
| LUnit, LUnit -> 0
|
|
|
|
| LDate d1, LDate d2 ->
|
Add overloaded operators for the common operations
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`.
2022-11-29 11:47:53 +03:00
|
|
|
if o_lt_dat_dat d1 d2 then -1 else if o_eq_dat_dat d1 d2 then 0 else 1
|
2022-08-25 13:09:51 +03:00
|
|
|
| LDuration d1, LDuration d2 -> (
|
|
|
|
(* Duration comparison in the runtime may fail, so rely on a basic
|
|
|
|
lexicographic comparison instead *)
|
|
|
|
let y1, m1, d1 = Runtime.duration_to_years_months_days d1 in
|
|
|
|
let y2, m2, d2 = Runtime.duration_to_years_months_days d2 in
|
|
|
|
match compare y1 y2 with
|
|
|
|
| 0 -> ( match compare m1 m2 with 0 -> compare d1 d2 | n -> n)
|
|
|
|
| n -> n)
|
|
|
|
| LBool _, _ -> -1
|
|
|
|
| _, LBool _ -> 1
|
|
|
|
| LInt _, _ -> -1
|
|
|
|
| _, LInt _ -> 1
|
|
|
|
| LRat _, _ -> -1
|
|
|
|
| _, LRat _ -> 1
|
|
|
|
| LMoney _, _ -> -1
|
|
|
|
| _, LMoney _ -> 1
|
|
|
|
| LUnit, _ -> -1
|
|
|
|
| _, LUnit -> 1
|
|
|
|
| LDate _, _ -> -1
|
|
|
|
| _, LDate _ -> 1
|
|
|
|
| LDuration _, _ -> .
|
|
|
|
| _, LDuration _ -> .
|
2022-08-17 12:49:16 +03:00
|
|
|
|
2022-08-25 17:08:08 +03:00
|
|
|
let compare_location
|
|
|
|
(type a)
|
2023-05-17 16:44:57 +03:00
|
|
|
(x : a glocation Mark.pos)
|
|
|
|
(y : a glocation Mark.pos) =
|
|
|
|
match Mark.remove x, Mark.remove y with
|
2023-08-16 01:04:45 +03:00
|
|
|
| ( DesugaredScopeVar { name = vx; state = None },
|
|
|
|
DesugaredScopeVar { name = vy; state = None } )
|
|
|
|
| ( DesugaredScopeVar { name = vx; state = Some _ },
|
|
|
|
DesugaredScopeVar { name = vy; state = None } )
|
|
|
|
| ( DesugaredScopeVar { name = vx; state = None },
|
|
|
|
DesugaredScopeVar { name = vy; state = Some _ } ) ->
|
2023-05-17 16:44:57 +03:00
|
|
|
ScopeVar.compare (Mark.remove vx) (Mark.remove vy)
|
2023-08-16 01:04:45 +03:00
|
|
|
| ( DesugaredScopeVar { name = x, _; state = Some sx },
|
|
|
|
DesugaredScopeVar { name = y, _; state = Some sy } ) ->
|
2022-08-25 17:08:08 +03:00
|
|
|
let cmp = ScopeVar.compare x y in
|
|
|
|
if cmp = 0 then StateName.compare sx sy else cmp
|
2023-08-16 01:04:45 +03:00
|
|
|
| ScopelangScopeVar { name = vx, _ }, ScopelangScopeVar { name = vy, _ } ->
|
2022-08-25 17:08:08 +03:00
|
|
|
ScopeVar.compare vx vy
|
2023-08-16 01:04:45 +03:00
|
|
|
| ( SubScopeVar { alias = xsubindex, _; var = xsubvar, _; _ },
|
|
|
|
SubScopeVar { alias = ysubindex, _; var = ysubvar, _; _ } ) ->
|
2022-08-25 17:08:08 +03:00
|
|
|
let c = SubScopeName.compare xsubindex ysubindex in
|
|
|
|
if c = 0 then ScopeVar.compare xsubvar ysubvar else c
|
2023-08-31 11:07:57 +03:00
|
|
|
| ToplevelVar { name = vx, _ }, ToplevelVar { name = vy, _ } ->
|
2023-08-30 18:49:29 +03:00
|
|
|
TopdefName.compare vx vy
|
2022-08-25 17:08:08 +03:00
|
|
|
| DesugaredScopeVar _, _ -> -1
|
|
|
|
| _, DesugaredScopeVar _ -> 1
|
|
|
|
| ScopelangScopeVar _, _ -> -1
|
|
|
|
| _, ScopelangScopeVar _ -> 1
|
2023-01-23 14:19:36 +03:00
|
|
|
| SubScopeVar _, _ -> -1
|
|
|
|
| _, SubScopeVar _ -> 1
|
2023-02-13 17:00:23 +03:00
|
|
|
| ToplevelVar _, _ -> .
|
|
|
|
| _, ToplevelVar _ -> .
|
2022-08-25 17:08:08 +03:00
|
|
|
|
|
|
|
let equal_location a b = compare_location a b = 0
|
2022-08-17 12:49:16 +03:00
|
|
|
let equal_except ex1 ex2 = ex1 = ex2
|
2022-08-25 13:09:51 +03:00
|
|
|
let compare_except ex1 ex2 = Stdlib.compare ex1 ex2
|
2023-08-16 01:04:45 +03:00
|
|
|
|
|
|
|
let equal_external_ref ref1 ref2 =
|
|
|
|
match ref1, ref2 with
|
2023-08-10 17:52:39 +03:00
|
|
|
| External_value v1, External_value v2 -> TopdefName.equal v1 v2
|
|
|
|
| External_scope s1, External_scope s2 -> ScopeName.equal s1 s2
|
|
|
|
| (External_value _ | External_scope _), _ -> false
|
2023-08-16 01:04:45 +03:00
|
|
|
|
|
|
|
let compare_external_ref ref1 ref2 =
|
|
|
|
match ref1, ref2 with
|
2023-08-10 17:52:39 +03:00
|
|
|
| External_value v1, External_value v2 -> TopdefName.compare v1 v2
|
|
|
|
| External_scope s1, External_scope s2 -> ScopeName.compare s1 s2
|
|
|
|
| External_value _, _ -> -1
|
|
|
|
| _, External_value _ -> 1
|
|
|
|
| External_scope _, _ -> .
|
|
|
|
| _, External_scope _ -> .
|
2022-08-17 12:49:16 +03:00
|
|
|
|
|
|
|
(* weird indentation; see
|
|
|
|
https://github.com/ocaml-ppx/ocamlformat/issues/2143 *)
|
2022-08-25 20:46:13 +03:00
|
|
|
let rec equal_list : 'a. ('a, 't) gexpr list -> ('a, 't) gexpr list -> bool =
|
2023-08-16 01:04:45 +03:00
|
|
|
fun es1 es2 -> List.equal equal es1 es2
|
2022-08-17 12:49:16 +03:00
|
|
|
|
2022-08-25 17:31:32 +03:00
|
|
|
and equal : type a. (a, 't) gexpr -> (a, 't) gexpr -> bool =
|
2022-08-22 19:53:30 +03:00
|
|
|
fun e1 e2 ->
|
2023-05-17 16:44:57 +03:00
|
|
|
match Mark.remove e1, Mark.remove e2 with
|
2022-08-22 19:53:30 +03:00
|
|
|
| EVar v1, EVar v2 -> Bindlib.eq_vars v1 v2
|
2023-08-30 18:49:29 +03:00
|
|
|
| EExternal { name = n1 }, EExternal { name = n2 } ->
|
|
|
|
Mark.equal equal_external_ref n1 n2
|
2022-11-17 19:13:35 +03:00
|
|
|
| ETuple es1, ETuple es2 -> equal_list es1 es2
|
|
|
|
| ( ETupleAccess { e = e1; index = id1; size = s1 },
|
|
|
|
ETupleAccess { e = e2; index = id2; size = s2 } ) ->
|
|
|
|
s1 = s2 && equal e1 e2 && id1 = id2
|
2022-08-22 19:53:30 +03:00
|
|
|
| EArray es1, EArray es2 -> equal_list es1 es2
|
|
|
|
| ELit l1, ELit l2 -> l1 = l2
|
2022-11-17 19:13:35 +03:00
|
|
|
| EAbs { binder = b1; tys = tys1 }, EAbs { binder = b2; tys = tys2 } ->
|
2023-05-02 12:59:39 +03:00
|
|
|
Type.equal_list tys1 tys2 && Bindlib.eq_mbinder equal b1 b2
|
2022-11-17 19:13:35 +03:00
|
|
|
| EApp { f = e1; args = args1 }, EApp { f = e2; args = args2 } ->
|
|
|
|
equal e1 e2 && equal_list args1 args2
|
2022-08-22 19:53:30 +03:00
|
|
|
| EAssert e1, EAssert e2 -> equal e1 e2
|
Add overloaded operators for the common operations
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`.
2022-11-29 11:47:53 +03:00
|
|
|
| EOp { op = op1; tys = tys1 }, EOp { op = op2; tys = tys2 } ->
|
|
|
|
Operator.equal op1 op2 && Type.equal_list tys1 tys2
|
2022-11-17 19:13:35 +03:00
|
|
|
| ( EDefault { excepts = exc1; just = def1; cons = cons1 },
|
|
|
|
EDefault { excepts = exc2; just = def2; cons = cons2 } ) ->
|
2022-08-22 19:53:30 +03:00
|
|
|
equal def1 def2 && equal cons1 cons2 && equal_list exc1 exc2
|
2022-11-17 19:13:35 +03:00
|
|
|
| ( EIfThenElse { cond = if1; etrue = then1; efalse = else1 },
|
|
|
|
EIfThenElse { cond = if2; etrue = then2; efalse = else2 } ) ->
|
2022-08-22 19:53:30 +03:00
|
|
|
equal if1 if2 && equal then1 then2 && equal else1 else2
|
2023-03-30 19:53:07 +03:00
|
|
|
| EEmptyError, EEmptyError -> true
|
2022-11-17 19:13:35 +03:00
|
|
|
| EErrorOnEmpty e1, EErrorOnEmpty e2 -> equal e1 e2
|
2022-08-22 19:53:30 +03:00
|
|
|
| ERaise ex1, ERaise ex2 -> equal_except ex1 ex2
|
2022-11-17 19:13:35 +03:00
|
|
|
| ( ECatch { body = etry1; exn = ex1; handler = ewith1 },
|
|
|
|
ECatch { body = etry2; exn = ex2; handler = ewith2 } ) ->
|
2022-08-22 19:53:30 +03:00
|
|
|
equal etry1 etry2 && equal_except ex1 ex2 && equal ewith1 ewith2
|
2022-08-25 17:08:08 +03:00
|
|
|
| ELocation l1, ELocation l2 ->
|
2023-05-17 16:44:57 +03:00
|
|
|
equal_location (Mark.add Pos.no_pos l1) (Mark.add Pos.no_pos l2)
|
2022-11-17 19:13:35 +03:00
|
|
|
| ( EStruct { name = s1; fields = fields1 },
|
|
|
|
EStruct { name = s2; fields = fields2 } ) ->
|
2022-11-21 12:12:45 +03:00
|
|
|
StructName.equal s1 s2 && StructField.Map.equal equal fields1 fields2
|
2023-08-30 18:49:29 +03:00
|
|
|
| ( EDStructAccess { e = e1; field = f1; name_opt = s1 },
|
|
|
|
EDStructAccess { e = e2; field = f2; name_opt = s2 } ) ->
|
2023-08-31 11:07:57 +03:00
|
|
|
Option.equal StructName.equal s1 s2 && Ident.equal f1 f2 && equal e1 e2
|
2022-11-17 19:13:35 +03:00
|
|
|
| ( EStructAccess { e = e1; field = f1; name = s1 },
|
|
|
|
EStructAccess { e = e2; field = f2; name = s2 } ) ->
|
2022-11-21 12:12:45 +03:00
|
|
|
StructName.equal s1 s2 && StructField.equal f1 f2 && equal e1 e2
|
2023-08-16 01:04:45 +03:00
|
|
|
| EInj { e = e1; cons = c1; name = n1 }, EInj { e = e2; cons = c2; name = n2 }
|
|
|
|
->
|
2022-08-17 19:14:30 +03:00
|
|
|
EnumName.equal n1 n2 && EnumConstructor.equal c1 c2 && equal e1 e2
|
2022-11-17 19:13:35 +03:00
|
|
|
| ( EMatch { e = e1; name = n1; cases = cases1 },
|
|
|
|
EMatch { e = e2; name = n2; cases = cases2 } ) ->
|
2022-08-17 19:14:30 +03:00
|
|
|
EnumName.equal n1 n2
|
|
|
|
&& equal e1 e2
|
2022-11-21 12:12:45 +03:00
|
|
|
&& EnumConstructor.Map.equal equal cases1 cases2
|
2023-08-30 18:49:29 +03:00
|
|
|
| ( EScopeCall { scope = s1; args = fields1 },
|
|
|
|
EScopeCall { scope = s2; args = fields2 } ) ->
|
2023-08-31 11:07:57 +03:00
|
|
|
ScopeName.equal s1 s2 && ScopeVar.Map.equal equal fields1 fields2
|
2023-04-19 19:26:50 +03:00
|
|
|
| ( ECustom { obj = obj1; targs = targs1; tret = tret1 },
|
|
|
|
ECustom { obj = obj2; targs = targs2; tret = tret2 } ) ->
|
|
|
|
Type.equal_list targs1 targs2 && Type.equal tret1 tret2 && obj1 == obj2
|
|
|
|
| ( ( EVar _ | EExternal _ | ETuple _ | ETupleAccess _ | EArray _ | ELit _
|
|
|
|
| EAbs _ | EApp _ | EAssert _ | EOp _ | EDefault _ | EIfThenElse _
|
|
|
|
| EEmptyError | EErrorOnEmpty _ | ERaise _ | ECatch _ | ELocation _
|
|
|
|
| EStruct _ | EDStructAccess _ | EStructAccess _ | EInj _ | EMatch _
|
|
|
|
| EScopeCall _ | ECustom _ ),
|
2022-08-22 19:53:30 +03:00
|
|
|
_ ) ->
|
|
|
|
false
|
|
|
|
|
2022-08-25 17:31:32 +03:00
|
|
|
let rec compare : type a. (a, _) gexpr -> (a, _) gexpr -> int =
|
2022-08-25 13:09:51 +03:00
|
|
|
fun e1 e2 ->
|
|
|
|
(* Infix operator to chain comparisons lexicographically. *)
|
|
|
|
let ( @@< ) cmp1 cmpf = match cmp1 with 0 -> cmpf () | n -> n in
|
|
|
|
(* OCamlformat doesn't know to keep consistency in match cases so disabled
|
|
|
|
locally for readability *)
|
2023-05-17 16:44:57 +03:00
|
|
|
match[@ocamlformat "disable"] Mark.remove e1, Mark.remove e2 with
|
2022-08-25 13:09:51 +03:00
|
|
|
| ELit l1, ELit l2 ->
|
|
|
|
compare_lit l1 l2
|
2022-11-22 22:57:59 +03:00
|
|
|
| EApp {f=f1; args=args1}, EApp {f=f2; args=args2} ->
|
2022-08-25 13:09:51 +03:00
|
|
|
compare f1 f2 @@< fun () ->
|
|
|
|
List.compare compare args1 args2
|
Add overloaded operators for the common operations
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`.
2022-11-29 11:47:53 +03:00
|
|
|
| EOp {op=op1; tys=tys1}, EOp {op=op2; tys=tys2} ->
|
|
|
|
Operator.compare op1 op2 @@< fun () ->
|
|
|
|
List.compare Type.compare tys1 tys2
|
2022-08-25 13:09:51 +03:00
|
|
|
| EArray a1, EArray a2 ->
|
|
|
|
List.compare compare a1 a2
|
|
|
|
| EVar v1, EVar v2 ->
|
|
|
|
Bindlib.compare_vars v1 v2
|
2023-08-30 18:49:29 +03:00
|
|
|
| EExternal { name = n1 }, EExternal { name = n2 } ->
|
|
|
|
Mark.compare compare_external_ref n1 n2
|
2022-11-22 22:57:59 +03:00
|
|
|
| EAbs {binder=binder1; tys=typs1},
|
|
|
|
EAbs {binder=binder2; tys=typs2} ->
|
Add overloaded operators for the common operations
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`.
2022-11-29 11:47:53 +03:00
|
|
|
List.compare Type.compare typs1 typs2 @@< fun () ->
|
2022-08-25 13:09:51 +03:00
|
|
|
let _, e1, e2 = Bindlib.unmbind2 binder1 binder2 in
|
|
|
|
compare e1 e2
|
2022-11-22 22:57:59 +03:00
|
|
|
| EIfThenElse {cond=i1; etrue=t1; efalse=e1},
|
|
|
|
EIfThenElse {cond=i2; etrue=t2; efalse=e2} ->
|
2022-08-25 13:09:51 +03:00
|
|
|
compare i1 i2 @@< fun () ->
|
|
|
|
compare t1 t2 @@< fun () ->
|
|
|
|
compare e1 e2
|
2022-08-25 17:08:08 +03:00
|
|
|
| ELocation l1, ELocation l2 ->
|
2023-05-17 16:44:57 +03:00
|
|
|
compare_location (Mark.add Pos.no_pos l1) (Mark.add Pos.no_pos l2)
|
2023-08-10 17:52:39 +03:00
|
|
|
| EStruct {name=name1; fields=field_map1 },
|
|
|
|
EStruct {name=name2; fields=field_map2 } ->
|
2022-08-25 13:09:51 +03:00
|
|
|
StructName.compare name1 name2 @@< fun () ->
|
2022-11-21 12:12:45 +03:00
|
|
|
StructField.Map.compare compare field_map1 field_map2
|
2023-08-30 18:49:29 +03:00
|
|
|
| EDStructAccess {e=e1; field=field_name1; name_opt=struct_name1},
|
|
|
|
EDStructAccess {e=e2; field=field_name2; name_opt=struct_name2} ->
|
2022-11-22 22:57:59 +03:00
|
|
|
compare e1 e2 @@< fun () ->
|
2023-04-18 15:39:38 +03:00
|
|
|
Ident.compare field_name1 field_name2 @@< fun () ->
|
2022-11-22 22:57:59 +03:00
|
|
|
Option.compare StructName.compare struct_name1 struct_name2
|
2023-08-10 17:52:39 +03:00
|
|
|
| EStructAccess {e=e1; field=field_name1; name=struct_name1 },
|
|
|
|
EStructAccess {e=e2; field=field_name2; name=struct_name2 } ->
|
2022-08-25 13:09:51 +03:00
|
|
|
compare e1 e2 @@< fun () ->
|
2022-11-21 12:12:45 +03:00
|
|
|
StructField.compare field_name1 field_name2 @@< fun () ->
|
2022-08-25 13:09:51 +03:00
|
|
|
StructName.compare struct_name1 struct_name2
|
2023-08-10 17:52:39 +03:00
|
|
|
| EMatch {e=e1; name=name1; cases=emap1 },
|
|
|
|
EMatch {e=e2; name=name2; cases=emap2 } ->
|
2022-08-25 13:09:51 +03:00
|
|
|
EnumName.compare name1 name2 @@< fun () ->
|
|
|
|
compare e1 e2 @@< fun () ->
|
2022-11-21 12:12:45 +03:00
|
|
|
EnumConstructor.Map.compare compare emap1 emap2
|
2023-08-30 18:49:29 +03:00
|
|
|
| EScopeCall {scope=name1; args=field_map1},
|
|
|
|
EScopeCall {scope=name2; args=field_map2} ->
|
2022-10-21 16:47:17 +03:00
|
|
|
ScopeName.compare name1 name2 @@< fun () ->
|
2022-11-21 12:12:45 +03:00
|
|
|
ScopeVar.Map.compare compare field_map1 field_map2
|
2022-11-17 19:13:35 +03:00
|
|
|
| ETuple es1, ETuple es2 ->
|
2022-08-25 13:09:51 +03:00
|
|
|
List.compare compare es1 es2
|
2022-11-22 22:57:59 +03:00
|
|
|
| ETupleAccess {e=e1; index=n1; size=s1},
|
|
|
|
ETupleAccess {e=e2; index=n2; size=s2} ->
|
2022-11-17 19:13:35 +03:00
|
|
|
Int.compare s1 s2 @@< fun () ->
|
2022-08-25 13:09:51 +03:00
|
|
|
Int.compare n1 n2 @@< fun () ->
|
|
|
|
compare e1 e2
|
2023-08-10 17:52:39 +03:00
|
|
|
| EInj {e=e1; name=name1; cons=cons1 },
|
|
|
|
EInj {e=e2; name=name2; cons=cons2 } ->
|
2022-08-25 13:09:51 +03:00
|
|
|
EnumName.compare name1 name2 @@< fun () ->
|
2022-11-17 19:13:35 +03:00
|
|
|
EnumConstructor.compare cons1 cons2 @@< fun () ->
|
2022-08-25 13:09:51 +03:00
|
|
|
compare e1 e2
|
|
|
|
| EAssert e1, EAssert e2 ->
|
|
|
|
compare e1 e2
|
2022-11-22 22:57:59 +03:00
|
|
|
| EDefault {excepts=exs1; just=just1; cons=cons1},
|
|
|
|
EDefault {excepts=exs2; just=just2; cons=cons2} ->
|
2022-08-25 13:09:51 +03:00
|
|
|
compare just1 just2 @@< fun () ->
|
|
|
|
compare cons1 cons2 @@< fun () ->
|
|
|
|
List.compare compare exs1 exs2
|
2023-03-30 19:53:07 +03:00
|
|
|
| EEmptyError, EEmptyError -> 0
|
2022-11-17 19:13:35 +03:00
|
|
|
| EErrorOnEmpty e1, EErrorOnEmpty e2 ->
|
2022-08-25 13:09:51 +03:00
|
|
|
compare e1 e2
|
|
|
|
| ERaise ex1, ERaise ex2 ->
|
|
|
|
compare_except ex1 ex2
|
2022-11-22 22:57:59 +03:00
|
|
|
| ECatch {body=etry1; exn=ex1; handler=ewith1},
|
|
|
|
ECatch {body=etry2; exn=ex2; handler=ewith2} ->
|
2022-08-25 13:09:51 +03:00
|
|
|
compare_except ex1 ex2 @@< fun () ->
|
|
|
|
compare etry1 etry2 @@< fun () ->
|
|
|
|
compare ewith1 ewith2
|
2023-04-19 19:26:50 +03:00
|
|
|
| ECustom _, _ | _, ECustom _ ->
|
|
|
|
(* fixme: ideally this would be forbidden by typing *)
|
|
|
|
invalid_arg "Custom block comparison"
|
2022-08-25 13:09:51 +03:00
|
|
|
| ELit _, _ -> -1 | _, ELit _ -> 1
|
|
|
|
| EApp _, _ -> -1 | _, EApp _ -> 1
|
|
|
|
| EOp _, _ -> -1 | _, EOp _ -> 1
|
|
|
|
| EArray _, _ -> -1 | _, EArray _ -> 1
|
|
|
|
| EVar _, _ -> -1 | _, EVar _ -> 1
|
2023-04-19 19:26:50 +03:00
|
|
|
| EExternal _, _ -> -1 | _, EExternal _ -> 1
|
2022-08-25 13:09:51 +03:00
|
|
|
| EAbs _, _ -> -1 | _, EAbs _ -> 1
|
|
|
|
| EIfThenElse _, _ -> -1 | _, EIfThenElse _ -> 1
|
|
|
|
| ELocation _, _ -> -1 | _, ELocation _ -> 1
|
|
|
|
| EStruct _, _ -> -1 | _, EStruct _ -> 1
|
2022-11-22 22:57:59 +03:00
|
|
|
| EDStructAccess _, _ -> -1 | _, EDStructAccess _ -> 1
|
2022-08-25 13:09:51 +03:00
|
|
|
| EStructAccess _, _ -> -1 | _, EStructAccess _ -> 1
|
2022-11-17 19:13:35 +03:00
|
|
|
| EMatch _, _ -> -1 | _, EMatch _ -> 1
|
2022-10-21 16:47:17 +03:00
|
|
|
| EScopeCall _, _ -> -1 | _, EScopeCall _ -> 1
|
2022-08-25 13:09:51 +03:00
|
|
|
| ETuple _, _ -> -1 | _, ETuple _ -> 1
|
|
|
|
| ETupleAccess _, _ -> -1 | _, ETupleAccess _ -> 1
|
|
|
|
| EInj _, _ -> -1 | _, EInj _ -> 1
|
|
|
|
| EAssert _, _ -> -1 | _, EAssert _ -> 1
|
|
|
|
| EDefault _, _ -> -1 | _, EDefault _ -> 1
|
2023-03-30 19:53:07 +03:00
|
|
|
| EEmptyError , _ -> -1 | _, EEmptyError -> 1
|
2023-03-30 16:30:08 +03:00
|
|
|
| EErrorOnEmpty _, _ -> -1 | _, EErrorOnEmpty _ -> 1
|
2022-08-25 13:09:51 +03:00
|
|
|
| ERaise _, _ -> -1 | _, ERaise _ -> 1
|
|
|
|
| ECatch _, _ -> . | _, ECatch _ -> .
|
|
|
|
|
2023-03-30 16:30:08 +03:00
|
|
|
let rec free_vars : ('a, 't) gexpr -> ('a, 't) gexpr Var.Set.t = function
|
2022-10-10 16:15:36 +03:00
|
|
|
| EVar v, _ -> Var.Set.singleton v
|
2022-11-17 19:13:35 +03:00
|
|
|
| EAbs { binder; _ }, _ ->
|
2022-08-22 19:53:30 +03:00
|
|
|
let vs, body = Bindlib.unmbind binder in
|
|
|
|
Array.fold_right Var.Set.remove vs (free_vars body)
|
2022-10-10 16:15:36 +03:00
|
|
|
| e -> shallow_fold (fun e -> Var.Set.union (free_vars e)) e Var.Set.empty
|
2022-08-17 12:49:16 +03:00
|
|
|
|
2023-03-27 17:55:52 +03:00
|
|
|
let rec skip_wrappers : type a. (a, 'm) gexpr -> (a, 'm) gexpr = function
|
|
|
|
| EApp { f = EOp { op = Log _; _ }, _; args = [e] }, _ -> skip_wrappers e
|
2023-05-02 12:59:39 +03:00
|
|
|
| EApp { f = EApp { f = EOp { op = Log _; _ }, _; args = [f] }, _; args }, m
|
|
|
|
->
|
|
|
|
skip_wrappers (EApp { f; args }, m)
|
2023-03-27 17:55:52 +03:00
|
|
|
| EErrorOnEmpty e, _ -> skip_wrappers e
|
2023-05-02 12:59:39 +03:00
|
|
|
| EDefault { excepts = []; just = ELit (LBool true), _; cons = e }, _ ->
|
|
|
|
skip_wrappers e
|
2023-03-27 17:55:52 +03:00
|
|
|
| e -> e
|
|
|
|
|
2022-08-17 12:49:16 +03:00
|
|
|
let remove_logging_calls e =
|
2022-11-17 19:13:35 +03:00
|
|
|
let rec f e =
|
2023-05-02 12:59:39 +03:00
|
|
|
let e, m = map ~f e in
|
|
|
|
( Bindlib.box_apply
|
|
|
|
(function
|
|
|
|
| EApp { f = EOp { op = Log _; _ }, _; args = [(arg, _)] } -> arg
|
|
|
|
| e -> e)
|
|
|
|
e,
|
|
|
|
m )
|
2022-08-17 12:49:16 +03:00
|
|
|
in
|
2022-11-17 19:13:35 +03:00
|
|
|
f e
|
2022-08-17 12:49:16 +03:00
|
|
|
|
2023-07-11 18:10:00 +03:00
|
|
|
module DefaultBindlibCtxRename = struct
|
|
|
|
(* This code is a copy-paste from Bindlib, they forgot to expose the default
|
|
|
|
implementation ! *)
|
|
|
|
type ctxt = int String.Map.t
|
|
|
|
|
|
|
|
let empty_ctxt = String.Map.empty
|
|
|
|
|
|
|
|
let split_name : string -> string * int =
|
|
|
|
fun name ->
|
|
|
|
let len = String.length name in
|
|
|
|
(* [i] is the index of the first first character of the suffix. *)
|
|
|
|
let i =
|
|
|
|
let is_digit c = '0' <= c && c <= '9' in
|
|
|
|
let first_digit = ref len in
|
|
|
|
let first_non_0 = ref len in
|
|
|
|
while !first_digit > 0 && is_digit name.[!first_digit - 1] do
|
|
|
|
decr first_digit;
|
|
|
|
if name.[!first_digit] <> '0' then first_non_0 := !first_digit
|
|
|
|
done;
|
|
|
|
!first_non_0
|
|
|
|
in
|
|
|
|
if i = len then name, 0
|
|
|
|
else String.sub name 0 i, int_of_string (String.sub name i (len - i))
|
|
|
|
|
|
|
|
let get_suffix : string -> int -> ctxt -> int * ctxt =
|
|
|
|
fun name suffix ctxt ->
|
2023-08-15 17:57:52 +03:00
|
|
|
let n = try String.Map.find name ctxt with String.Map.Not_found _ -> -1 in
|
2023-07-11 18:10:00 +03:00
|
|
|
let suffix = if suffix > n then suffix else n + 1 in
|
|
|
|
suffix, String.Map.add name suffix ctxt
|
|
|
|
|
|
|
|
let merge_name : string -> int -> string =
|
|
|
|
fun prefix suffix ->
|
|
|
|
if suffix > 0 then prefix ^ string_of_int suffix else prefix
|
|
|
|
|
|
|
|
let new_name : string -> ctxt -> string * ctxt =
|
|
|
|
fun name ctxt ->
|
|
|
|
let prefix, suffix = split_name name in
|
|
|
|
let suffix, ctxt = get_suffix prefix suffix ctxt in
|
|
|
|
merge_name prefix suffix, ctxt
|
|
|
|
|
|
|
|
let reserve_name : string -> ctxt -> ctxt =
|
|
|
|
fun name ctxt ->
|
|
|
|
let prefix, suffix = split_name name in
|
|
|
|
try
|
|
|
|
let n = String.Map.find prefix ctxt in
|
|
|
|
if suffix <= n then ctxt else String.Map.add prefix suffix ctxt
|
2023-08-15 17:57:52 +03:00
|
|
|
with String.Map.Not_found _ -> String.Map.add prefix suffix ctxt
|
2023-07-11 18:10:00 +03:00
|
|
|
end
|
|
|
|
|
|
|
|
let rename_vars
|
|
|
|
?(exclude = ([] : string list))
|
|
|
|
?(reset_context_for_closed_terms = false)
|
|
|
|
?(skip_constant_binders = false)
|
|
|
|
?(constant_binder_name = None)
|
|
|
|
e =
|
|
|
|
let module BindCtx = Bindlib.Ctxt (struct
|
|
|
|
include DefaultBindlibCtxRename
|
|
|
|
|
|
|
|
let reset_context_for_closed_terms = reset_context_for_closed_terms
|
|
|
|
let skip_constant_binders = skip_constant_binders
|
|
|
|
let constant_binder_name = constant_binder_name
|
|
|
|
end) in
|
|
|
|
let rec aux : type a. BindCtx.ctxt -> (a, 't) gexpr -> (a, 't) gexpr boxed =
|
|
|
|
fun ctx e ->
|
|
|
|
match e with
|
|
|
|
| EAbs { binder; tys }, m ->
|
|
|
|
let vars, body, ctx = BindCtx.unmbind_in ctx binder in
|
|
|
|
let body = aux ctx body in
|
|
|
|
let binder = bind vars body in
|
|
|
|
eabs binder tys m
|
|
|
|
| e -> map ~f:(aux ctx) e
|
|
|
|
in
|
|
|
|
let ctx =
|
|
|
|
List.fold_left
|
|
|
|
(fun ctx name -> DefaultBindlibCtxRename.reserve_name name ctx)
|
|
|
|
BindCtx.empty_ctxt exclude
|
|
|
|
in
|
|
|
|
aux ctx e
|
|
|
|
|
2023-05-02 17:33:23 +03:00
|
|
|
let format ppf e = Print.expr ~debug:false () ppf e
|
2022-08-17 17:14:14 +03:00
|
|
|
|
2022-08-25 20:46:13 +03:00
|
|
|
let rec size : type a. (a, 't) gexpr -> int =
|
2022-08-22 19:53:30 +03:00
|
|
|
fun e ->
|
2023-05-17 16:44:57 +03:00
|
|
|
match Mark.remove e with
|
2023-04-19 19:26:50 +03:00
|
|
|
| EVar _ | EExternal _ | ELit _ | EOp _ | EEmptyError | ECustom _ -> 1
|
2022-11-17 19:13:35 +03:00
|
|
|
| ETuple args -> List.fold_left (fun acc arg -> acc + size arg) 1 args
|
2022-08-22 19:53:30 +03:00
|
|
|
| EArray args -> List.fold_left (fun acc arg -> acc + size arg) 1 args
|
2022-11-17 19:13:35 +03:00
|
|
|
| ETupleAccess { e; _ } -> size e + 1
|
|
|
|
| EInj { e; _ } -> size e + 1
|
|
|
|
| EAssert e -> size e + 1
|
|
|
|
| EErrorOnEmpty e -> size e + 1
|
|
|
|
| EApp { f; args } ->
|
|
|
|
List.fold_left (fun acc arg -> acc + size arg) (1 + size f) args
|
|
|
|
| EAbs { binder; _ } ->
|
2022-08-22 19:53:30 +03:00
|
|
|
let _, body = Bindlib.unmbind binder in
|
|
|
|
1 + size body
|
2022-11-17 19:13:35 +03:00
|
|
|
| EIfThenElse { cond; etrue; efalse } ->
|
|
|
|
1 + size cond + size etrue + size efalse
|
|
|
|
| EDefault { excepts; just; cons } ->
|
2022-08-22 19:53:30 +03:00
|
|
|
List.fold_left
|
|
|
|
(fun acc except -> acc + size except)
|
|
|
|
(1 + size just + size cons)
|
2022-11-17 19:13:35 +03:00
|
|
|
excepts
|
2022-08-22 19:53:30 +03:00
|
|
|
| ERaise _ -> 1
|
2022-11-17 19:13:35 +03:00
|
|
|
| ECatch { body; handler; _ } -> 1 + size body + size handler
|
2022-08-17 19:14:30 +03:00
|
|
|
| ELocation _ -> 1
|
2022-11-17 19:13:35 +03:00
|
|
|
| EStruct { fields; _ } ->
|
2022-11-21 12:12:45 +03:00
|
|
|
StructField.Map.fold (fun _ e acc -> acc + 1 + size e) fields 0
|
2022-11-22 22:57:59 +03:00
|
|
|
| EDStructAccess { e; _ } -> 1 + size e
|
2022-11-17 19:13:35 +03:00
|
|
|
| EStructAccess { e; _ } -> 1 + size e
|
|
|
|
| EMatch { e; cases; _ } ->
|
2022-11-21 12:12:45 +03:00
|
|
|
EnumConstructor.Map.fold (fun _ e acc -> acc + 1 + size e) cases (size e)
|
2022-11-17 19:13:35 +03:00
|
|
|
| EScopeCall { args; _ } ->
|
2022-11-21 12:12:45 +03:00
|
|
|
ScopeVar.Map.fold (fun _ e acc -> acc + 1 + size e) args 1
|
2022-09-12 18:03:44 +03:00
|
|
|
|
|
|
|
(* - Expression building helpers - *)
|
|
|
|
|
Swap boxing and annotations in expressions
This was the only reasonable solution I found to the issue raised
[here](https://github.com/CatalaLang/catala/pull/334#discussion_r987175884).
This was a pretty tedious rewrite, but it should now ensure we are doing things
correctly. As a bonus, the "smart" expression constructors are now used
everywhere to build expressions (so another refactoring like this one should be
much easier) and this makes the code overall feel more
straightforward (`Bindlib.box_apply` or `let+` no longer need to be visible!)
---
Basically, we were using values of type `gexpr box = naked_gexpr marked box`
throughout when (re-)building expressions. This was done 99% of the time by
using `Bindlib.box_apply add_mark naked_e` right after building `naked_e`. In
lots of places, we needed to recover the annotation of this expression later on,
typically to build its parent term (to inherit the position, or build the type).
Since it wasn't always possible to wrap these uses within `box_apply` (esp. as
bindlib boxes aren't a monad), here and there we had to call `Bindlib.unbox`,
just to recover the position or type. This had the very unpleasant effect of
forcing the resolution of the whole box (including applying any stored closures)
to reach the top-level annotation which isn't even dependant on specific
variable bindings. Then, generally, throwing away the result.
Therefore, the change proposed here transforms
- `naked_gexpr marked Bindlib.box` into
- `naked_gexpr Bindlib.box marked` (aliased to `boxed_gexpr` or `gexpr boxed` for
convenience)
This means only
1. not fitting the mark into the box right away when building, and
2. accessing the top-level mark directly without unboxing
The functions for building terms from module `Shared_ast.Expr` could be changed
easily. But then they needed to be consistently used throughout, without
manually building terms through `Bindlib.apply_box` -- which covers most of the
changes in this patch.
`Expr.Box.inj` is provided to swap back to a box, before binding for example.
Additionally, this gives a 40% speedup on `make -C examples pass_all_tests`,
which hints at the amount of unnecessary work we were doing --'
2022-10-06 20:13:45 +03:00
|
|
|
let make_var v mark = evar v mark
|
2022-09-12 18:03:44 +03:00
|
|
|
|
|
|
|
let make_abs xs e taus pos =
|
|
|
|
let mark =
|
|
|
|
map_mark
|
|
|
|
(fun _ -> pos)
|
2023-05-17 16:44:57 +03:00
|
|
|
(fun ety -> Mark.add pos (TArrow (taus, ety)))
|
|
|
|
(Mark.get e)
|
2022-09-12 18:03:44 +03:00
|
|
|
in
|
Swap boxing and annotations in expressions
This was the only reasonable solution I found to the issue raised
[here](https://github.com/CatalaLang/catala/pull/334#discussion_r987175884).
This was a pretty tedious rewrite, but it should now ensure we are doing things
correctly. As a bonus, the "smart" expression constructors are now used
everywhere to build expressions (so another refactoring like this one should be
much easier) and this makes the code overall feel more
straightforward (`Bindlib.box_apply` or `let+` no longer need to be visible!)
---
Basically, we were using values of type `gexpr box = naked_gexpr marked box`
throughout when (re-)building expressions. This was done 99% of the time by
using `Bindlib.box_apply add_mark naked_e` right after building `naked_e`. In
lots of places, we needed to recover the annotation of this expression later on,
typically to build its parent term (to inherit the position, or build the type).
Since it wasn't always possible to wrap these uses within `box_apply` (esp. as
bindlib boxes aren't a monad), here and there we had to call `Bindlib.unbox`,
just to recover the position or type. This had the very unpleasant effect of
forcing the resolution of the whole box (including applying any stored closures)
to reach the top-level annotation which isn't even dependant on specific
variable bindings. Then, generally, throwing away the result.
Therefore, the change proposed here transforms
- `naked_gexpr marked Bindlib.box` into
- `naked_gexpr Bindlib.box marked` (aliased to `boxed_gexpr` or `gexpr boxed` for
convenience)
This means only
1. not fitting the mark into the box right away when building, and
2. accessing the top-level mark directly without unboxing
The functions for building terms from module `Shared_ast.Expr` could be changed
easily. But then they needed to be consistently used throughout, without
manually building terms through `Bindlib.apply_box` -- which covers most of the
changes in this patch.
`Expr.Box.inj` is provided to swap back to a box, before binding for example.
Additionally, this gives a 40% speedup on `make -C examples pass_all_tests`,
which hints at the amount of unnecessary work we were doing --'
2022-10-06 20:13:45 +03:00
|
|
|
eabs (bind xs e) taus mark
|
2022-09-12 18:03:44 +03:00
|
|
|
|
2023-04-24 15:55:39 +03:00
|
|
|
let make_app e args pos =
|
Swap boxing and annotations in expressions
This was the only reasonable solution I found to the issue raised
[here](https://github.com/CatalaLang/catala/pull/334#discussion_r987175884).
This was a pretty tedious rewrite, but it should now ensure we are doing things
correctly. As a bonus, the "smart" expression constructors are now used
everywhere to build expressions (so another refactoring like this one should be
much easier) and this makes the code overall feel more
straightforward (`Bindlib.box_apply` or `let+` no longer need to be visible!)
---
Basically, we were using values of type `gexpr box = naked_gexpr marked box`
throughout when (re-)building expressions. This was done 99% of the time by
using `Bindlib.box_apply add_mark naked_e` right after building `naked_e`. In
lots of places, we needed to recover the annotation of this expression later on,
typically to build its parent term (to inherit the position, or build the type).
Since it wasn't always possible to wrap these uses within `box_apply` (esp. as
bindlib boxes aren't a monad), here and there we had to call `Bindlib.unbox`,
just to recover the position or type. This had the very unpleasant effect of
forcing the resolution of the whole box (including applying any stored closures)
to reach the top-level annotation which isn't even dependant on specific
variable bindings. Then, generally, throwing away the result.
Therefore, the change proposed here transforms
- `naked_gexpr marked Bindlib.box` into
- `naked_gexpr Bindlib.box marked` (aliased to `boxed_gexpr` or `gexpr boxed` for
convenience)
This means only
1. not fitting the mark into the box right away when building, and
2. accessing the top-level mark directly without unboxing
The functions for building terms from module `Shared_ast.Expr` could be changed
easily. But then they needed to be consistently used throughout, without
manually building terms through `Bindlib.apply_box` -- which covers most of the
changes in this patch.
`Expr.Box.inj` is provided to swap back to a box, before binding for example.
Additionally, this gives a 40% speedup on `make -C examples pass_all_tests`,
which hints at the amount of unnecessary work we were doing --'
2022-10-06 20:13:45 +03:00
|
|
|
let mark =
|
|
|
|
fold_marks
|
|
|
|
(fun _ -> pos)
|
|
|
|
(function
|
|
|
|
| [] -> assert false
|
2023-01-12 17:12:11 +03:00
|
|
|
| fty :: argtys -> (
|
2023-05-17 16:44:57 +03:00
|
|
|
match Mark.remove fty.ty with
|
2023-01-12 17:12:11 +03:00
|
|
|
| TArrow (tx', tr) ->
|
2023-02-22 14:11:42 +03:00
|
|
|
assert (Type.unifiable_list tx' (List.map (fun x -> x.ty) argtys));
|
2023-01-12 17:12:11 +03:00
|
|
|
tr
|
|
|
|
| TAny -> fty.ty
|
2023-04-24 15:55:39 +03:00
|
|
|
| _ ->
|
2023-06-13 12:27:45 +03:00
|
|
|
Message.raise_internal_error
|
2023-04-24 15:55:39 +03:00
|
|
|
"wrong type: found %a while expecting either an Arrow or Any"
|
|
|
|
Print.typ_debug fty.ty))
|
2023-05-17 16:44:57 +03:00
|
|
|
(List.map Mark.get (e :: args))
|
Swap boxing and annotations in expressions
This was the only reasonable solution I found to the issue raised
[here](https://github.com/CatalaLang/catala/pull/334#discussion_r987175884).
This was a pretty tedious rewrite, but it should now ensure we are doing things
correctly. As a bonus, the "smart" expression constructors are now used
everywhere to build expressions (so another refactoring like this one should be
much easier) and this makes the code overall feel more
straightforward (`Bindlib.box_apply` or `let+` no longer need to be visible!)
---
Basically, we were using values of type `gexpr box = naked_gexpr marked box`
throughout when (re-)building expressions. This was done 99% of the time by
using `Bindlib.box_apply add_mark naked_e` right after building `naked_e`. In
lots of places, we needed to recover the annotation of this expression later on,
typically to build its parent term (to inherit the position, or build the type).
Since it wasn't always possible to wrap these uses within `box_apply` (esp. as
bindlib boxes aren't a monad), here and there we had to call `Bindlib.unbox`,
just to recover the position or type. This had the very unpleasant effect of
forcing the resolution of the whole box (including applying any stored closures)
to reach the top-level annotation which isn't even dependant on specific
variable bindings. Then, generally, throwing away the result.
Therefore, the change proposed here transforms
- `naked_gexpr marked Bindlib.box` into
- `naked_gexpr Bindlib.box marked` (aliased to `boxed_gexpr` or `gexpr boxed` for
convenience)
This means only
1. not fitting the mark into the box right away when building, and
2. accessing the top-level mark directly without unboxing
The functions for building terms from module `Shared_ast.Expr` could be changed
easily. But then they needed to be consistently used throughout, without
manually building terms through `Bindlib.apply_box` -- which covers most of the
changes in this patch.
`Expr.Box.inj` is provided to swap back to a box, before binding for example.
Additionally, this gives a 40% speedup on `make -C examples pass_all_tests`,
which hints at the amount of unnecessary work we were doing --'
2022-10-06 20:13:45 +03:00
|
|
|
in
|
2023-01-12 17:12:11 +03:00
|
|
|
eapp e args mark
|
2022-09-12 18:03:44 +03:00
|
|
|
|
2023-04-11 18:46:41 +03:00
|
|
|
let thunk_term term mark =
|
2022-09-12 18:03:44 +03:00
|
|
|
let silent = Var.make "_" in
|
|
|
|
let pos = mark_pos mark in
|
2023-04-11 18:46:41 +03:00
|
|
|
make_abs [| silent |] term [TLit TUnit, pos] pos
|
|
|
|
|
|
|
|
let empty_thunked_term mark = thunk_term (Bindlib.box EEmptyError, mark) mark
|
|
|
|
|
|
|
|
let unthunk_term_nobox term mark =
|
2023-05-17 16:44:57 +03:00
|
|
|
Mark.add mark (EApp { f = term; args = [ELit LUnit, mark] })
|
2022-09-12 18:03:44 +03:00
|
|
|
|
|
|
|
let make_let_in x tau e1 e2 mpos =
|
Swap boxing and annotations in expressions
This was the only reasonable solution I found to the issue raised
[here](https://github.com/CatalaLang/catala/pull/334#discussion_r987175884).
This was a pretty tedious rewrite, but it should now ensure we are doing things
correctly. As a bonus, the "smart" expression constructors are now used
everywhere to build expressions (so another refactoring like this one should be
much easier) and this makes the code overall feel more
straightforward (`Bindlib.box_apply` or `let+` no longer need to be visible!)
---
Basically, we were using values of type `gexpr box = naked_gexpr marked box`
throughout when (re-)building expressions. This was done 99% of the time by
using `Bindlib.box_apply add_mark naked_e` right after building `naked_e`. In
lots of places, we needed to recover the annotation of this expression later on,
typically to build its parent term (to inherit the position, or build the type).
Since it wasn't always possible to wrap these uses within `box_apply` (esp. as
bindlib boxes aren't a monad), here and there we had to call `Bindlib.unbox`,
just to recover the position or type. This had the very unpleasant effect of
forcing the resolution of the whole box (including applying any stored closures)
to reach the top-level annotation which isn't even dependant on specific
variable bindings. Then, generally, throwing away the result.
Therefore, the change proposed here transforms
- `naked_gexpr marked Bindlib.box` into
- `naked_gexpr Bindlib.box marked` (aliased to `boxed_gexpr` or `gexpr boxed` for
convenience)
This means only
1. not fitting the mark into the box right away when building, and
2. accessing the top-level mark directly without unboxing
The functions for building terms from module `Shared_ast.Expr` could be changed
easily. But then they needed to be consistently used throughout, without
manually building terms through `Bindlib.apply_box` -- which covers most of the
changes in this patch.
`Expr.Box.inj` is provided to swap back to a box, before binding for example.
Additionally, this gives a 40% speedup on `make -C examples pass_all_tests`,
which hints at the amount of unnecessary work we were doing --'
2022-10-06 20:13:45 +03:00
|
|
|
make_app (make_abs [| x |] e2 [tau] mpos) [e1] (pos e2)
|
2022-09-12 18:03:44 +03:00
|
|
|
|
|
|
|
let make_multiple_let_in xs taus e1s e2 mpos =
|
Swap boxing and annotations in expressions
This was the only reasonable solution I found to the issue raised
[here](https://github.com/CatalaLang/catala/pull/334#discussion_r987175884).
This was a pretty tedious rewrite, but it should now ensure we are doing things
correctly. As a bonus, the "smart" expression constructors are now used
everywhere to build expressions (so another refactoring like this one should be
much easier) and this makes the code overall feel more
straightforward (`Bindlib.box_apply` or `let+` no longer need to be visible!)
---
Basically, we were using values of type `gexpr box = naked_gexpr marked box`
throughout when (re-)building expressions. This was done 99% of the time by
using `Bindlib.box_apply add_mark naked_e` right after building `naked_e`. In
lots of places, we needed to recover the annotation of this expression later on,
typically to build its parent term (to inherit the position, or build the type).
Since it wasn't always possible to wrap these uses within `box_apply` (esp. as
bindlib boxes aren't a monad), here and there we had to call `Bindlib.unbox`,
just to recover the position or type. This had the very unpleasant effect of
forcing the resolution of the whole box (including applying any stored closures)
to reach the top-level annotation which isn't even dependant on specific
variable bindings. Then, generally, throwing away the result.
Therefore, the change proposed here transforms
- `naked_gexpr marked Bindlib.box` into
- `naked_gexpr Bindlib.box marked` (aliased to `boxed_gexpr` or `gexpr boxed` for
convenience)
This means only
1. not fitting the mark into the box right away when building, and
2. accessing the top-level mark directly without unboxing
The functions for building terms from module `Shared_ast.Expr` could be changed
easily. But then they needed to be consistently used throughout, without
manually building terms through `Bindlib.apply_box` -- which covers most of the
changes in this patch.
`Expr.Box.inj` is provided to swap back to a box, before binding for example.
Additionally, this gives a 40% speedup on `make -C examples pass_all_tests`,
which hints at the amount of unnecessary work we were doing --'
2022-10-06 20:13:45 +03:00
|
|
|
make_app (make_abs xs e2 taus mpos) e1s (pos e2)
|
2022-09-12 18:03:44 +03:00
|
|
|
|
2022-11-17 19:13:35 +03:00
|
|
|
let make_default_unboxed excepts just cons =
|
2022-09-12 18:03:44 +03:00
|
|
|
let rec bool_value = function
|
|
|
|
| ELit (LBool b), _ -> Some b
|
Add overloaded operators for the common operations
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`.
2022-11-29 11:47:53 +03:00
|
|
|
| EApp { f = EOp { op = Log (l, _); _ }, _; args = [e]; _ }, _
|
2022-09-12 18:03:44 +03:00
|
|
|
when l <> PosRecordIfTrueBool
|
|
|
|
(* we don't remove the log calls corresponding to source code
|
|
|
|
definitions !*) ->
|
|
|
|
bool_value e
|
|
|
|
| _ -> None
|
|
|
|
in
|
2022-11-17 19:13:35 +03:00
|
|
|
match excepts, bool_value just, cons with
|
2023-04-21 15:35:10 +03:00
|
|
|
| excepts, Some true, (EDefault { excepts = []; just; cons }, _) ->
|
|
|
|
EDefault { excepts; just; cons }
|
2023-05-17 16:44:57 +03:00
|
|
|
| [((EDefault _, _) as except)], Some false, _ -> Mark.remove except
|
2022-11-17 19:13:35 +03:00
|
|
|
| excepts, _, cons -> EDefault { excepts; just; cons }
|
Swap boxing and annotations in expressions
This was the only reasonable solution I found to the issue raised
[here](https://github.com/CatalaLang/catala/pull/334#discussion_r987175884).
This was a pretty tedious rewrite, but it should now ensure we are doing things
correctly. As a bonus, the "smart" expression constructors are now used
everywhere to build expressions (so another refactoring like this one should be
much easier) and this makes the code overall feel more
straightforward (`Bindlib.box_apply` or `let+` no longer need to be visible!)
---
Basically, we were using values of type `gexpr box = naked_gexpr marked box`
throughout when (re-)building expressions. This was done 99% of the time by
using `Bindlib.box_apply add_mark naked_e` right after building `naked_e`. In
lots of places, we needed to recover the annotation of this expression later on,
typically to build its parent term (to inherit the position, or build the type).
Since it wasn't always possible to wrap these uses within `box_apply` (esp. as
bindlib boxes aren't a monad), here and there we had to call `Bindlib.unbox`,
just to recover the position or type. This had the very unpleasant effect of
forcing the resolution of the whole box (including applying any stored closures)
to reach the top-level annotation which isn't even dependant on specific
variable bindings. Then, generally, throwing away the result.
Therefore, the change proposed here transforms
- `naked_gexpr marked Bindlib.box` into
- `naked_gexpr Bindlib.box marked` (aliased to `boxed_gexpr` or `gexpr boxed` for
convenience)
This means only
1. not fitting the mark into the box right away when building, and
2. accessing the top-level mark directly without unboxing
The functions for building terms from module `Shared_ast.Expr` could be changed
easily. But then they needed to be consistently used throughout, without
manually building terms through `Bindlib.apply_box` -- which covers most of the
changes in this patch.
`Expr.Box.inj` is provided to swap back to a box, before binding for example.
Additionally, this gives a 40% speedup on `make -C examples pass_all_tests`,
which hints at the amount of unnecessary work we were doing --'
2022-10-06 20:13:45 +03:00
|
|
|
|
|
|
|
let make_default exceptions just cons =
|
|
|
|
Box.app2n just cons exceptions
|
|
|
|
@@ fun just cons exceptions -> make_default_unboxed exceptions just cons
|
2022-10-03 18:07:06 +03:00
|
|
|
|
2022-11-17 19:13:35 +03:00
|
|
|
let make_tuple el m0 =
|
2022-10-03 18:07:06 +03:00
|
|
|
match el with
|
2022-11-17 19:13:35 +03:00
|
|
|
| [] -> etuple [] (with_ty m0 (TTuple [], mark_pos m0))
|
2022-10-03 18:07:06 +03:00
|
|
|
| el ->
|
|
|
|
let m =
|
|
|
|
fold_marks
|
|
|
|
(fun posl -> List.hd posl)
|
2022-11-17 19:13:35 +03:00
|
|
|
(fun ml -> TTuple (List.map (fun t -> t.ty) ml), (List.hd ml).pos)
|
2023-05-17 16:44:57 +03:00
|
|
|
(List.map (fun e -> Mark.get e) el)
|
2022-10-03 18:07:06 +03:00
|
|
|
in
|
2022-11-17 19:13:35 +03:00
|
|
|
etuple el m
|