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-08-12 18:59:49 +03:00
|
|
|
open 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 =
|
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
|
|
|
fun em ->
|
|
|
|
B.box_apply (fun e -> Marked.mark (Marked.get_mark em) e) (Marked.unmark em)
|
2022-10-21 16:33:05 +03:00
|
|
|
|
|
|
|
module LiftStruct = Bindlib.Lift (StructFieldMap)
|
|
|
|
|
|
|
|
let lift_struct = LiftStruct.lift_box
|
|
|
|
|
|
|
|
module LiftEnum = Bindlib.Lift (EnumConstructorMap)
|
|
|
|
|
|
|
|
let lift_enum = LiftEnum.lift_box
|
|
|
|
|
|
|
|
module LiftScopeVars = Bindlib.Lift (ScopeVarMap)
|
|
|
|
|
|
|
|
let lift_scope_vars = LiftScopeVars.lift_box
|
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 =
|
|
|
|
Bindlib.msubst binder (Array.of_list (List.map Marked.unmark vars))
|
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 evar v mark = Marked.mark mark (Bindlib.box_var v)
|
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
|
|
|
|
let elit l mark = Marked.mark mark (Bindlib.box (ELit l))
|
|
|
|
|
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
|
|
|
|
let eop op = Box.app0 @@ EOp op
|
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
|
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 }
|
|
|
|
|
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
|
|
|
|
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 estruct name (fields : ('a, 't) boxed_gexpr StructFieldMap.t) mark =
|
|
|
|
Marked.mark mark
|
|
|
|
@@ Bindlib.box_apply
|
2022-11-17 19:13:35 +03:00
|
|
|
(fun fields -> EStruct { name; fields })
|
2022-10-21 16:33:05 +03:00
|
|
|
(Box.lift_struct (StructFieldMap.map Box.lift fields))
|
2022-08-17 19:14:30 +03:00
|
|
|
|
2022-11-17 19:13:35 +03:00
|
|
|
let estructaccess e field name =
|
|
|
|
Box.app1 e @@ fun e -> EStructAccess { name; e; field }
|
2022-08-17 19:14:30 +03:00
|
|
|
|
2022-11-17 19:13:35 +03:00
|
|
|
let einj e cons name = Box.app1 e @@ fun e -> EInj { name; e; cons }
|
2022-08-17 19:14:30 +03:00
|
|
|
|
2022-11-17 19:13:35 +03:00
|
|
|
let ematch e name cases 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
|
|
|
Marked.mark mark
|
|
|
|
@@ Bindlib.box_apply2
|
2022-11-17 19:13:35 +03:00
|
|
|
(fun e cases -> EMatch { name; e; cases })
|
|
|
|
(Box.lift e)
|
2022-10-21 16:33:05 +03:00
|
|
|
(Box.lift_enum (EnumConstructorMap.map Box.lift cases))
|
2022-07-28 11:36:36 +03:00
|
|
|
|
2022-11-17 19:13:35 +03:00
|
|
|
let escopecall scope args mark =
|
2022-10-21 16:47:17 +03:00
|
|
|
Marked.mark mark
|
|
|
|
@@ Bindlib.box_apply
|
2022-11-17 19:13:35 +03:00
|
|
|
(fun args -> EScopeCall { scope; args })
|
|
|
|
(Box.lift_scope_vars (ScopeVarMap.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 }
|
|
|
|
| Typed _ -> Typed { pos = Pos.no_pos; ty = Marked.mark Pos.no_pos TAny }
|
|
|
|
|
|
|
|
let mark_pos (type m) (m : m mark) : Pos.t =
|
|
|
|
match m with Untyped { pos } | Typed { pos; _ } -> pos
|
|
|
|
|
2022-08-16 17:54:42 +03:00
|
|
|
let pos (type m) (x : ('a, m mark) Marked.t) : Pos.t =
|
|
|
|
mark_pos (Marked.get_mark x)
|
|
|
|
|
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
|
|
|
|
2022-09-12 18:03:44 +03:00
|
|
|
let set_ty (type m) (ty : typ) (x : ('a, m mark) Marked.t) :
|
2022-08-16 17:54:42 +03:00
|
|
|
('a, typed mark) Marked.t =
|
2022-08-12 23:42:39 +03:00
|
|
|
Marked.mark
|
|
|
|
(match Marked.get_mark x with
|
|
|
|
| Untyped { pos } -> Typed { pos; ty }
|
|
|
|
| Typed m -> Typed { m with ty })
|
|
|
|
(Marked.unmark x)
|
|
|
|
|
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 }
|
|
|
|
|
|
|
|
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 }
|
|
|
|
|
|
|
|
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) }
|
|
|
|
| Typed _ :: _ ->
|
|
|
|
Typed
|
|
|
|
{
|
|
|
|
pos = pos_f (List.map (function Typed { pos; _ } -> pos) ms);
|
|
|
|
ty = ty_f (List.map (function Typed m -> m) ms);
|
|
|
|
}
|
|
|
|
|
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 =
|
|
|
|
match m with Untyped { pos } -> Marked.mark pos typ | Typed { ty; _ } -> ty
|
|
|
|
|
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 *)
|
2022-08-12 18:59:49 +03:00
|
|
|
let map
|
2022-07-28 11:36:36 +03:00
|
|
|
(type a)
|
2022-11-17 19:13:35 +03:00
|
|
|
~(f : (a, 'm1) gexpr -> (a, 'm2) boxed_gexpr)
|
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
|
|
|
(e : ((a, 'm1) naked_gexpr, 'm2) Marked.t) : (a, 'm2) boxed_gexpr =
|
2022-07-28 11:36:36 +03:00
|
|
|
let m = Marked.get_mark e in
|
|
|
|
match Marked.unmark e with
|
|
|
|
| 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
|
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
|
|
|
| EOp op -> eop op 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
|
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
|
|
|
|
| EInj { e; name; cons } -> einj (f e) cons name m
|
|
|
|
| EAssert e1 -> eassert (f e1) m
|
|
|
|
| EDefault { excepts; just; cons } ->
|
|
|
|
edefault (List.map f excepts) (f just) (f cons) m
|
|
|
|
| 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
|
|
|
|
| ELocation loc -> elocation loc m
|
2022-11-17 19:13:35 +03:00
|
|
|
| EStruct { name; fields } ->
|
|
|
|
let fields = StructFieldMap.map f fields in
|
2022-08-17 19:14:30 +03:00
|
|
|
estruct name fields m
|
2022-11-17 19:13:35 +03:00
|
|
|
| EStructAccess { e; field; name } -> estructaccess (f e) field name m
|
|
|
|
| EMatch { e; name; cases } ->
|
|
|
|
let cases = EnumConstructorMap.map f cases in
|
|
|
|
ematch (f e) name cases m
|
|
|
|
| EScopeCall { scope; args } ->
|
|
|
|
let fields = ScopeVarMap.map f args in
|
|
|
|
escopecall scope fields 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)
|
2022-07-28 11:36:36 +03:00
|
|
|
|
2022-08-12 18:59:49 +03:00
|
|
|
let map_marks ~f e =
|
|
|
|
map_top_down ~f:(fun e -> Marked.(mark (f (get_mark e)) (unmark e))) e
|
2022-07-28 11:36:36 +03:00
|
|
|
|
2022-10-10 16:15:36 +03:00
|
|
|
(* Folds the given function on the direct children of the given expression. Does
|
|
|
|
not open binders. *)
|
|
|
|
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
|
|
|
|
match Marked.unmark e with
|
|
|
|
| ELit _ | EOp _ | EVar _ | ERaise _ | ELocation _ -> 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
|
|
|
|
| EAbs _ -> acc
|
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
|
|
|
|
| EStruct { fields; _ } -> acc |> StructFieldMap.fold (fun _ -> f) fields
|
|
|
|
| EStructAccess { e; _ } -> acc |> f e
|
|
|
|
| EMatch { e; cases; _ } ->
|
|
|
|
acc |> f e |> EnumConstructorMap.fold (fun _ -> f) cases
|
|
|
|
| EScopeCall { args; _ } -> acc |> ScopeVarMap.fold (fun _ -> f) args
|
|
|
|
|
|
|
|
(* 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)
|
|
|
|
(e : ((a, 'm1) naked_gexpr, 'm2) Marked.t) : 'acc * (a, 'm2) boxed_gexpr =
|
|
|
|
let m = Marked.get_mark e in
|
|
|
|
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
|
|
|
|
match Marked.unmark e with
|
|
|
|
| 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
|
|
|
|
| EOp op -> acc, eop op m
|
|
|
|
| EArray args ->
|
|
|
|
let acc, args = lfoldmap args in
|
|
|
|
acc, earray args m
|
|
|
|
| EVar v -> acc, evar (Var.translate v) m
|
|
|
|
| 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
|
|
|
|
| EInj { e; name; cons } ->
|
|
|
|
let acc, e = f e in
|
|
|
|
acc, einj e cons name m
|
|
|
|
| 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
|
|
|
|
| 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 =
|
|
|
|
StructFieldMap.fold
|
|
|
|
(fun cons e (acc, fields) ->
|
|
|
|
let acc1, e = f e in
|
|
|
|
join acc acc1, StructFieldMap.add cons e fields)
|
|
|
|
fields
|
|
|
|
(acc, StructFieldMap.empty)
|
|
|
|
in
|
|
|
|
acc, estruct name fields m
|
|
|
|
| EStructAccess { e; field; name } ->
|
|
|
|
let acc, e = f e in
|
|
|
|
acc, estructaccess e field name m
|
|
|
|
| EMatch { e; name; cases } ->
|
|
|
|
let acc, e = f e in
|
|
|
|
let acc, cases =
|
|
|
|
EnumConstructorMap.fold
|
|
|
|
(fun cons e (acc, cases) ->
|
|
|
|
let acc1, e = f e in
|
|
|
|
join acc acc1, EnumConstructorMap.add cons e cases)
|
|
|
|
cases
|
|
|
|
(acc, EnumConstructorMap.empty)
|
|
|
|
in
|
|
|
|
acc, ematch e name cases m
|
|
|
|
| EScopeCall { scope; args } ->
|
|
|
|
let acc, args =
|
|
|
|
ScopeVarMap.fold
|
|
|
|
(fun var e (acc, args) ->
|
|
|
|
let acc1, e = f e in
|
|
|
|
join acc acc1, ScopeVarMap.add var e args)
|
|
|
|
args (acc, ScopeVarMap.empty)
|
|
|
|
in
|
|
|
|
acc, escopecall scope args 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. *)
|
2022-11-17 19:13:35 +03:00
|
|
|
let rec rebox e = map ~f:rebox e
|
2022-08-12 23:42:39 +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 box e = Marked.same_mark_as (Bindlib.box (Marked.unmark e)) e
|
|
|
|
let unbox (e, m) = Bindlib.unbox e, m
|
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) =
|
2022-08-17 12:49:16 +03:00
|
|
|
match Marked.unmark e with
|
|
|
|
| ELit _ | EAbs _ | EOp _ | ERaise _ -> true
|
|
|
|
| _ -> false
|
|
|
|
|
2022-08-25 13:09:51 +03:00
|
|
|
let equal_tlit l1 l2 = l1 = l2
|
|
|
|
let compare_tlit l1 l2 = Stdlib.compare l1 l2
|
|
|
|
|
|
|
|
let rec equal_typ ty1 ty2 =
|
2022-08-17 12:49:16 +03:00
|
|
|
match Marked.unmark ty1, Marked.unmark ty2 with
|
2022-08-25 13:09:51 +03:00
|
|
|
| TLit l1, TLit l2 -> equal_tlit l1 l2
|
|
|
|
| TTuple tys1, TTuple tys2 -> equal_typ_list tys1 tys2
|
2022-08-23 16:23:52 +03:00
|
|
|
| TStruct n1, TStruct n2 -> StructName.equal n1 n2
|
|
|
|
| TEnum n1, TEnum n2 -> EnumName.equal n1 n2
|
2022-08-25 13:09:51 +03:00
|
|
|
| TOption t1, TOption t2 -> equal_typ t1 t2
|
|
|
|
| TArrow (t1, t1'), TArrow (t2, t2') -> equal_typ t1 t2 && equal_typ t1' t2'
|
|
|
|
| TArray t1, TArray t2 -> equal_typ t1 t2
|
2022-08-17 12:49:16 +03:00
|
|
|
| TAny, TAny -> true
|
2022-08-23 16:23:52 +03:00
|
|
|
| ( ( TLit _ | TTuple _ | TStruct _ | TEnum _ | TOption _ | TArrow _
|
|
|
|
| TArray _ | TAny ),
|
|
|
|
_ ) ->
|
|
|
|
false
|
2022-08-17 12:49:16 +03:00
|
|
|
|
2022-08-25 13:09:51 +03:00
|
|
|
and equal_typ_list tys1 tys2 =
|
|
|
|
try List.for_all2 equal_typ tys1 tys2 with Invalid_argument _ -> false
|
|
|
|
|
2022-10-04 12:28:36 +03:00
|
|
|
(* Similar to [equal_typ], but allows TAny holes *)
|
|
|
|
let rec unifiable ty1 ty2 =
|
|
|
|
match Marked.unmark ty1, Marked.unmark ty2 with
|
|
|
|
| TAny, _ | _, TAny -> true
|
|
|
|
| TLit l1, TLit l2 -> equal_tlit l1 l2
|
|
|
|
| TTuple tys1, TTuple tys2 -> unifiable_list tys1 tys2
|
|
|
|
| TStruct n1, TStruct n2 -> StructName.equal n1 n2
|
|
|
|
| TEnum n1, TEnum n2 -> EnumName.equal n1 n2
|
|
|
|
| TOption t1, TOption t2 -> unifiable t1 t2
|
|
|
|
| TArrow (t1, t1'), TArrow (t2, t2') -> unifiable t1 t2 && unifiable t1' t2'
|
|
|
|
| TArray t1, TArray t2 -> unifiable t1 t2
|
|
|
|
| ( (TLit _ | TTuple _ | TStruct _ | TEnum _ | TOption _ | TArrow _ | TArray _),
|
|
|
|
_ ) ->
|
|
|
|
false
|
|
|
|
|
|
|
|
and unifiable_list tys1 tys2 =
|
|
|
|
try List.for_all2 unifiable tys1 tys2 with Invalid_argument _ -> false
|
2022-09-28 13:28:48 +03:00
|
|
|
|
2022-08-25 13:09:51 +03:00
|
|
|
let rec compare_typ ty1 ty2 =
|
|
|
|
match Marked.unmark ty1, Marked.unmark ty2 with
|
|
|
|
| TLit l1, TLit l2 -> compare_tlit l1 l2
|
|
|
|
| TTuple tys1, TTuple tys2 -> List.compare compare_typ tys1 tys2
|
|
|
|
| TStruct n1, TStruct n2 -> StructName.compare n1 n2
|
|
|
|
| TEnum en1, TEnum en2 -> EnumName.compare en1 en2
|
|
|
|
| TOption t1, TOption t2 -> compare_typ t1 t2
|
|
|
|
| TArrow (a1, b1), TArrow (a2, b2) -> (
|
|
|
|
match compare_typ a1 a2 with 0 -> compare_typ b1 b2 | n -> n)
|
|
|
|
| TArray t1, TArray t2 -> compare_typ t1 t2
|
|
|
|
| TAny, TAny -> 0
|
|
|
|
| TLit _, _ -> -1
|
|
|
|
| _, TLit _ -> 1
|
|
|
|
| TTuple _, _ -> -1
|
|
|
|
| _, TTuple _ -> 1
|
|
|
|
| TStruct _, _ -> -1
|
|
|
|
| _, TStruct _ -> 1
|
|
|
|
| TEnum _, _ -> -1
|
|
|
|
| _, TEnum _ -> 1
|
|
|
|
| TOption _, _ -> -1
|
|
|
|
| _, TOption _ -> 1
|
|
|
|
| TArrow _, _ -> -1
|
|
|
|
| _, TArrow _ -> 1
|
|
|
|
| TArray _, _ -> -1
|
|
|
|
| _, TArray _ -> 1
|
|
|
|
|
|
|
|
let equal_lit (type a) (l1 : a glit) (l2 : a glit) =
|
|
|
|
match l1, l2 with
|
|
|
|
| LBool b1, LBool b2 -> Bool.equal b1 b2
|
|
|
|
| LEmptyError, LEmptyError -> true
|
|
|
|
| LInt n1, LInt n2 -> Runtime.( =! ) n1 n2
|
|
|
|
| LRat r1, LRat r2 -> Runtime.( =& ) r1 r2
|
|
|
|
| LMoney m1, LMoney m2 -> Runtime.( =$ ) m1 m2
|
|
|
|
| LUnit, LUnit -> true
|
|
|
|
| LDate d1, LDate d2 -> Runtime.( =@ ) d1 d2
|
|
|
|
| LDuration d1, LDuration d2 -> Runtime.( =^ ) d1 d2
|
|
|
|
| ( ( LBool _ | LEmptyError | LInt _ | LRat _ | LMoney _ | LUnit | LDate _
|
|
|
|
| LDuration _ ),
|
|
|
|
_ ) ->
|
|
|
|
false
|
|
|
|
|
|
|
|
let compare_lit (type a) (l1 : a glit) (l2 : a glit) =
|
|
|
|
match l1, l2 with
|
|
|
|
| LBool b1, LBool b2 -> Bool.compare b1 b2
|
|
|
|
| LEmptyError, LEmptyError -> 0
|
|
|
|
| LInt n1, LInt n2 ->
|
|
|
|
if Runtime.( <! ) n1 n2 then -1 else if Runtime.( =! ) n1 n2 then 0 else 1
|
|
|
|
| LRat r1, LRat r2 ->
|
|
|
|
if Runtime.( <& ) r1 r2 then -1 else if Runtime.( =& ) r1 r2 then 0 else 1
|
|
|
|
| LMoney m1, LMoney m2 ->
|
|
|
|
if Runtime.( <$ ) m1 m2 then -1 else if Runtime.( =$ ) m1 m2 then 0 else 1
|
|
|
|
| LUnit, LUnit -> 0
|
|
|
|
| LDate d1, LDate d2 ->
|
|
|
|
if Runtime.( <@ ) d1 d2 then -1 else if Runtime.( =@ ) d1 d2 then 0 else 1
|
|
|
|
| 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
|
|
|
|
| LEmptyError, _ -> -1
|
|
|
|
| _, LEmptyError -> 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)
|
|
|
|
(x : a glocation Marked.pos)
|
|
|
|
(y : a glocation Marked.pos) =
|
|
|
|
match Marked.unmark x, Marked.unmark y with
|
|
|
|
| DesugaredScopeVar (vx, None), DesugaredScopeVar (vy, None)
|
|
|
|
| DesugaredScopeVar (vx, Some _), DesugaredScopeVar (vy, None)
|
|
|
|
| DesugaredScopeVar (vx, None), DesugaredScopeVar (vy, Some _) ->
|
|
|
|
ScopeVar.compare (Marked.unmark vx) (Marked.unmark vy)
|
|
|
|
| DesugaredScopeVar ((x, _), Some sx), DesugaredScopeVar ((y, _), Some sy) ->
|
|
|
|
let cmp = ScopeVar.compare x y in
|
|
|
|
if cmp = 0 then StateName.compare sx sy else cmp
|
|
|
|
| ScopelangScopeVar (vx, _), ScopelangScopeVar (vy, _) ->
|
|
|
|
ScopeVar.compare vx vy
|
|
|
|
| ( SubScopeVar (_, (xsubindex, _), (xsubvar, _)),
|
|
|
|
SubScopeVar (_, (ysubindex, _), (ysubvar, _)) ) ->
|
|
|
|
let c = SubScopeName.compare xsubindex ysubindex in
|
|
|
|
if c = 0 then ScopeVar.compare xsubvar ysubvar else c
|
|
|
|
| DesugaredScopeVar _, _ -> -1
|
|
|
|
| _, DesugaredScopeVar _ -> 1
|
|
|
|
| ScopelangScopeVar _, _ -> -1
|
|
|
|
| _, ScopelangScopeVar _ -> 1
|
|
|
|
| SubScopeVar _, _ -> .
|
|
|
|
| _, SubScopeVar _ -> .
|
|
|
|
|
|
|
|
let equal_location a b = compare_location a b = 0
|
|
|
|
|
2022-08-17 12:49:16 +03:00
|
|
|
let equal_log_entries l1 l2 =
|
|
|
|
match l1, l2 with
|
2022-08-25 13:09:51 +03:00
|
|
|
| VarDef t1, VarDef t2 -> equal_typ (t1, Pos.no_pos) (t2, Pos.no_pos)
|
2022-08-17 12:49:16 +03:00
|
|
|
| x, y -> x = y
|
|
|
|
|
2022-08-25 13:09:51 +03:00
|
|
|
let compare_log_entries l1 l2 =
|
|
|
|
match l1, l2 with
|
|
|
|
| VarDef t1, VarDef t2 -> compare_typ (t1, Pos.no_pos) (t2, Pos.no_pos)
|
|
|
|
| BeginCall, BeginCall
|
|
|
|
| EndCall, EndCall
|
|
|
|
| PosRecordIfTrueBool, PosRecordIfTrueBool ->
|
|
|
|
0
|
|
|
|
| VarDef _, _ -> -1
|
|
|
|
| _, VarDef _ -> 1
|
|
|
|
| BeginCall, _ -> -1
|
|
|
|
| _, BeginCall -> 1
|
|
|
|
| EndCall, _ -> -1
|
|
|
|
| _, EndCall -> 1
|
|
|
|
| PosRecordIfTrueBool, _ -> .
|
|
|
|
| _, PosRecordIfTrueBool -> .
|
|
|
|
|
|
|
|
(* let equal_op_kind = Stdlib.(=) *)
|
|
|
|
|
|
|
|
let compare_op_kind = Stdlib.compare
|
|
|
|
|
2022-08-17 12:49:16 +03:00
|
|
|
let equal_unops op1 op2 =
|
|
|
|
match op1, op2 with
|
|
|
|
(* Log entries contain a typ which contain position information, we thus need
|
|
|
|
to descend into them *)
|
2022-08-25 13:09:51 +03:00
|
|
|
| Log (l1, info1), Log (l2, info2) ->
|
|
|
|
equal_log_entries l1 l2 && List.equal Uid.MarkedString.equal info1 info2
|
2022-08-22 19:53:30 +03:00
|
|
|
| Log _, _ | _, Log _ -> false
|
2022-08-17 12:49:16 +03:00
|
|
|
(* All the other cases can be discharged through equality *)
|
2022-08-22 19:53:30 +03:00
|
|
|
| ( ( Not | Minus _ | Length | IntToRat | MoneyToRat | RatToMoney | GetDay
|
|
|
|
| GetMonth | GetYear | FirstDayOfMonth | LastDayOfMonth | RoundMoney
|
|
|
|
| RoundDecimal ),
|
|
|
|
_ ) ->
|
|
|
|
op1 = op2
|
2022-08-17 12:49:16 +03:00
|
|
|
|
2022-08-25 13:09:51 +03:00
|
|
|
let compare_unops op1 op2 =
|
|
|
|
match op1, op2 with
|
|
|
|
| Not, Not -> 0
|
|
|
|
| Minus k1, Minus k2 -> compare_op_kind k1 k2
|
|
|
|
| Log (l1, info1), Log (l2, info2) -> (
|
|
|
|
match compare_log_entries l1 l2 with
|
|
|
|
| 0 -> List.compare Uid.MarkedString.compare info1 info2
|
|
|
|
| n -> n)
|
|
|
|
| Length, Length
|
|
|
|
| IntToRat, IntToRat
|
|
|
|
| MoneyToRat, MoneyToRat
|
|
|
|
| RatToMoney, RatToMoney
|
|
|
|
| GetDay, GetDay
|
|
|
|
| GetMonth, GetMonth
|
|
|
|
| GetYear, GetYear
|
|
|
|
| FirstDayOfMonth, FirstDayOfMonth
|
|
|
|
| LastDayOfMonth, LastDayOfMonth
|
|
|
|
| RoundMoney, RoundMoney
|
|
|
|
| RoundDecimal, RoundDecimal ->
|
|
|
|
0
|
|
|
|
| Not, _ -> -1
|
|
|
|
| _, Not -> 1
|
|
|
|
| Minus _, _ -> -1
|
|
|
|
| _, Minus _ -> 1
|
|
|
|
| Log _, _ -> -1
|
|
|
|
| _, Log _ -> 1
|
|
|
|
| Length, _ -> -1
|
|
|
|
| _, Length -> 1
|
|
|
|
| IntToRat, _ -> -1
|
|
|
|
| _, IntToRat -> 1
|
|
|
|
| MoneyToRat, _ -> -1
|
|
|
|
| _, MoneyToRat -> 1
|
|
|
|
| RatToMoney, _ -> -1
|
|
|
|
| _, RatToMoney -> 1
|
|
|
|
| GetDay, _ -> -1
|
|
|
|
| _, GetDay -> 1
|
|
|
|
| GetMonth, _ -> -1
|
|
|
|
| _, GetMonth -> 1
|
|
|
|
| GetYear, _ -> -1
|
|
|
|
| _, GetYear -> 1
|
|
|
|
| FirstDayOfMonth, _ -> -1
|
|
|
|
| _, FirstDayOfMonth -> 1
|
|
|
|
| LastDayOfMonth, _ -> -1
|
|
|
|
| _, LastDayOfMonth -> 1
|
|
|
|
| RoundMoney, _ -> -1
|
|
|
|
| _, RoundMoney -> 1
|
|
|
|
| RoundDecimal, _ -> .
|
|
|
|
| _, RoundDecimal -> .
|
|
|
|
|
|
|
|
let equal_binop = Stdlib.( = )
|
|
|
|
let compare_binop = Stdlib.compare
|
|
|
|
let equal_ternop = Stdlib.( = )
|
|
|
|
let compare_ternop = Stdlib.compare
|
|
|
|
|
2022-08-17 12:49:16 +03:00
|
|
|
let equal_ops op1 op2 =
|
|
|
|
match op1, op2 with
|
2022-08-25 13:09:51 +03:00
|
|
|
| Ternop op1, Ternop op2 -> equal_ternop op1 op2
|
|
|
|
| Binop op1, Binop op2 -> equal_binop op1 op2
|
2022-08-17 12:49:16 +03:00
|
|
|
| Unop op1, Unop op2 -> equal_unops op1 op2
|
|
|
|
| _, _ -> false
|
|
|
|
|
2022-08-25 13:09:51 +03:00
|
|
|
let compare_op op1 op2 =
|
|
|
|
match op1, op2 with
|
|
|
|
| Ternop op1, Ternop op2 -> compare_ternop op1 op2
|
|
|
|
| Binop op1, Binop op2 -> compare_binop op1 op2
|
|
|
|
| Unop op1, Unop op2 -> compare_unops op1 op2
|
|
|
|
| Ternop _, _ -> -1
|
|
|
|
| _, Ternop _ -> 1
|
|
|
|
| Binop _, _ -> -1
|
|
|
|
| _, Binop _ -> 1
|
|
|
|
| Unop _, _ -> .
|
|
|
|
| _, Unop _ -> .
|
|
|
|
|
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
|
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 =
|
2022-08-17 12:49:16 +03:00
|
|
|
fun es1 es2 ->
|
|
|
|
try List.for_all2 equal es1 es2 with Invalid_argument _ -> false
|
|
|
|
|
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 ->
|
|
|
|
match Marked.unmark e1, Marked.unmark e2 with
|
|
|
|
| EVar v1, EVar v2 -> Bindlib.eq_vars v1 v2
|
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 } ->
|
2022-08-25 13:09:51 +03:00
|
|
|
equal_typ_list tys1 tys2
|
2022-08-22 19:53:30 +03:00
|
|
|
&&
|
|
|
|
let vars1, body1 = Bindlib.unmbind b1 in
|
|
|
|
let body2 = Bindlib.msubst b2 (Array.map (fun x -> EVar x) vars1) in
|
|
|
|
equal body1 body2
|
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
|
|
|
|
| EOp op1, EOp op2 -> equal_ops op1 op2
|
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
|
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 ->
|
|
|
|
equal_location (Marked.mark Pos.no_pos l1) (Marked.mark Pos.no_pos l2)
|
2022-11-17 19:13:35 +03:00
|
|
|
| ( EStruct { name = s1; fields = fields1 },
|
|
|
|
EStruct { name = s2; fields = fields2 } ) ->
|
2022-08-17 19:14:30 +03:00
|
|
|
StructName.equal s1 s2 && StructFieldMap.equal equal fields1 fields2
|
2022-11-17 19:13:35 +03:00
|
|
|
| ( EStructAccess { e = e1; field = f1; name = s1 },
|
|
|
|
EStructAccess { e = e2; field = f2; name = s2 } ) ->
|
2022-08-17 19:14:30 +03:00
|
|
|
StructName.equal s1 s2 && StructFieldName.equal f1 f2 && equal e1 e2
|
2022-11-17 19:13:35 +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
|
|
|
|
&& EnumConstructorMap.equal equal cases1 cases2
|
2022-11-17 19:13:35 +03:00
|
|
|
| ( EScopeCall { scope = s1; args = fields1 },
|
|
|
|
EScopeCall { scope = s2; args = fields2 } ) ->
|
2022-10-21 16:47:17 +03:00
|
|
|
ScopeName.equal s1 s2 && ScopeVarMap.equal equal fields1 fields2
|
2022-11-17 19:13:35 +03:00
|
|
|
| ( ( EVar _ | ETuple _ | ETupleAccess _ | EArray _ | ELit _ | EAbs _ | EApp _
|
|
|
|
| EAssert _ | EOp _ | EDefault _ | EIfThenElse _ | EErrorOnEmpty _
|
|
|
|
| ERaise _ | ECatch _ | ELocation _ | EStruct _ | EStructAccess _ | EInj _
|
|
|
|
| EMatch _ | EScopeCall _ ),
|
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 *)
|
|
|
|
match[@ocamlformat "disable"] Marked.unmark e1, Marked.unmark e2 with
|
|
|
|
| ELit l1, ELit l2 ->
|
|
|
|
compare_lit l1 l2
|
2022-11-17 19:13:35 +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
|
|
|
|
| EOp op1, EOp op2 ->
|
|
|
|
compare_op op1 op2
|
|
|
|
| EArray a1, EArray a2 ->
|
|
|
|
List.compare compare a1 a2
|
|
|
|
| EVar v1, EVar v2 ->
|
|
|
|
Bindlib.compare_vars v1 v2
|
2022-11-17 19:13:35 +03:00
|
|
|
| EAbs {binder=binder1; tys= typs1}, EAbs {binder=binder2; tys= typs2} ->
|
2022-08-25 13:09:51 +03:00
|
|
|
List.compare compare_typ typs1 typs2 @@< fun () ->
|
|
|
|
let _, e1, e2 = Bindlib.unmbind2 binder1 binder2 in
|
|
|
|
compare e1 e2
|
2022-11-17 19:13:35 +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 ->
|
|
|
|
compare_location (Marked.mark Pos.no_pos l1) (Marked.mark Pos.no_pos l2)
|
2022-11-17 19:13:35 +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 () ->
|
|
|
|
StructFieldMap.compare compare field_map1 field_map2
|
2022-11-17 19:13:35 +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 () ->
|
|
|
|
StructFieldName.compare field_name1 field_name2 @@< fun () ->
|
|
|
|
StructName.compare struct_name1 struct_name2
|
2022-11-17 19:13:35 +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 () ->
|
|
|
|
EnumConstructorMap.compare compare emap1 emap2
|
2022-11-17 19:13:35 +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 () ->
|
|
|
|
ScopeVarMap.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-17 19:13:35 +03:00
|
|
|
| ETupleAccess {e=e1; index= n1; size=s1}, ETupleAccess {e=e2; index= n2; size=s2} ->
|
|
|
|
Int.compare s1 s2 @@< fun () ->
|
2022-08-25 13:09:51 +03:00
|
|
|
Int.compare n1 n2 @@< fun () ->
|
|
|
|
compare e1 e2
|
2022-11-17 19:13:35 +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-17 19:13:35 +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
|
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-17 19:13:35 +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
|
|
|
|
| ELit _, _ -> -1 | _, ELit _ -> 1
|
|
|
|
| EApp _, _ -> -1 | _, EApp _ -> 1
|
|
|
|
| EOp _, _ -> -1 | _, EOp _ -> 1
|
|
|
|
| EArray _, _ -> -1 | _, EArray _ -> 1
|
|
|
|
| EVar _, _ -> -1 | _, EVar _ -> 1
|
|
|
|
| EAbs _, _ -> -1 | _, EAbs _ -> 1
|
|
|
|
| EIfThenElse _, _ -> -1 | _, EIfThenElse _ -> 1
|
|
|
|
| ELocation _, _ -> -1 | _, ELocation _ -> 1
|
|
|
|
| EStruct _, _ -> -1 | _, EStruct _ -> 1
|
|
|
|
| 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
|
2022-11-17 19:13:35 +03:00
|
|
|
| EErrorOnEmpty _, _ -> . | _, EErrorOnEmpty _ -> .
|
2022-08-25 13:09:51 +03:00
|
|
|
| ERaise _, _ -> -1 | _, ERaise _ -> 1
|
|
|
|
| ECatch _, _ -> . | _, ECatch _ -> .
|
|
|
|
|
2022-10-10 16:15:36 +03:00
|
|
|
let rec free_vars : type a. (a, 't) gexpr -> (a, 't) gexpr Var.Set.t = function
|
|
|
|
| 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
|
|
|
|
|
|
|
let remove_logging_calls e =
|
2022-11-17 19:13:35 +03:00
|
|
|
let rec f e =
|
2022-08-17 12:49:16 +03:00
|
|
|
match Marked.unmark e with
|
2022-11-17 19:13:35 +03:00
|
|
|
| EApp { f = EOp (Unop (Log _)), _; args = [arg] } -> map ~f arg
|
|
|
|
| _ -> map ~f e
|
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
|
|
|
|
2022-09-26 17:05:57 +03:00
|
|
|
let format ?debug decl_ctx ppf e = Print.expr ?debug decl_ctx 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 ->
|
|
|
|
match Marked.unmark e with
|
|
|
|
| EVar _ | ELit _ | EOp _ -> 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-08-17 19:14:30 +03:00
|
|
|
StructFieldMap.fold (fun _ e acc -> acc + 1 + size e) fields 0
|
2022-11-17 19:13:35 +03:00
|
|
|
| EStructAccess { e; _ } -> 1 + size e
|
|
|
|
| EMatch { e; cases; _ } ->
|
|
|
|
EnumConstructorMap.fold (fun _ e acc -> acc + 1 + size e) cases (size e)
|
|
|
|
| EScopeCall { args; _ } ->
|
|
|
|
ScopeVarMap.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)
|
|
|
|
(fun ety ->
|
|
|
|
List.fold_right
|
|
|
|
(fun tx acc -> Marked.mark pos (TArrow (tx, acc)))
|
|
|
|
taus ety)
|
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
|
|
|
(Marked.get_mark 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
|
|
|
|
|
|
|
let make_app e u 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
|
|
|
|
| fty :: argtys ->
|
|
|
|
List.fold_left
|
|
|
|
(fun tf tx ->
|
|
|
|
match Marked.unmark tf with
|
|
|
|
| TArrow (tx', tr) ->
|
|
|
|
assert (unifiable tx.ty tx');
|
|
|
|
(* wrong arg type *)
|
|
|
|
tr
|
|
|
|
| TAny -> tf
|
|
|
|
| _ -> assert false)
|
|
|
|
fty.ty argtys)
|
|
|
|
(List.map Marked.get_mark (e :: u))
|
|
|
|
in
|
|
|
|
eapp e u mark
|
2022-09-12 18:03:44 +03:00
|
|
|
|
|
|
|
let empty_thunked_term mark =
|
|
|
|
let silent = Var.make "_" in
|
|
|
|
let pos = mark_pos mark in
|
2022-10-03 18:07:06 +03:00
|
|
|
make_abs [| silent |]
|
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 (ELit LEmptyError), mark)
|
2022-10-03 18:07:06 +03:00
|
|
|
[TLit TUnit, pos]
|
|
|
|
pos
|
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
|
2022-11-17 19:13:35 +03:00
|
|
|
| EApp { f = EOp (Unop (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
|
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
|
|
|
| [], Some true, cons -> Marked.unmark cons
|
2022-11-17 19:13:35 +03:00
|
|
|
| excepts, Some true, (EDefault { excepts = []; just; 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
|
|
|
| [except], Some false, _ -> Marked.unmark 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)
|
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
|
|
|
(List.map (fun e -> Marked.get_mark e) el)
|
2022-10-03 18:07:06 +03:00
|
|
|
in
|
2022-11-17 19:13:35 +03:00
|
|
|
etuple el m
|