2022-01-07 20:36:56 +03:00
|
|
|
(* This file is part of the Catala compiler, a specification language for tax
|
2022-01-10 12:59:30 +03:00
|
|
|
and social benefits computation rules. Copyright (C) 2022 Inria,
|
2022-01-07 20:36:56 +03:00
|
|
|
contributors: Alain Delaët <alain.delaet--tixeuil@inria.fr>, Denis Merigoux
|
|
|
|
<denis.merigoux@inria.fr>
|
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
|
|
use this file except in compliance with the License. You may obtain a copy of
|
|
|
|
the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
|
|
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
|
|
License for the specific language governing permissions and limitations under
|
|
|
|
the License. *)
|
2022-11-21 12:46:17 +03:00
|
|
|
open Catala_utils
|
2022-08-12 23:42:39 +03:00
|
|
|
open Shared_ast
|
2022-01-07 20:36:56 +03:00
|
|
|
open Ast
|
|
|
|
|
2022-01-31 16:30:42 +03:00
|
|
|
type partial_evaluation_ctx = {
|
2022-08-25 20:46:13 +03:00
|
|
|
var_values : (typed expr, typed expr) Var.Map.t;
|
2022-01-31 16:30:42 +03:00
|
|
|
decl_ctx : decl_ctx;
|
|
|
|
}
|
2022-01-07 20:36:56 +03:00
|
|
|
|
2022-08-25 17:35:08 +03:00
|
|
|
let rec partial_evaluation (ctx : partial_evaluation_ctx) (e : 'm expr) :
|
2022-11-17 19:13:35 +03:00
|
|
|
(dcalc, 'm mark) boxed_gexpr =
|
|
|
|
(* We proceed bottom-up, first apply on the subterms *)
|
|
|
|
let e = Expr.map ~f:(partial_evaluation ctx) e in
|
2022-09-27 17:27:26 +03:00
|
|
|
let mark = Marked.get_mark e in
|
2022-11-17 19:13:35 +03:00
|
|
|
(* Then reduce the parent node *)
|
2023-03-30 19:53:07 +03:00
|
|
|
let reduce (e : 'm expr) =
|
2022-11-17 19:13:35 +03:00
|
|
|
(* Todo: improve the handling of eapp(log,elit) cases here, it obfuscates
|
|
|
|
the matches and the log calls are not preserved, which would be a good
|
|
|
|
property *)
|
|
|
|
match Marked.unmark e with
|
|
|
|
| EApp
|
|
|
|
{
|
|
|
|
f =
|
Add overloaded operators for the common operations
This uses the same disambiguation mechanism put in place for
structures, calling the typer on individual rules on the desugared AST
to propagate types, in order to resolve ambiguous operators like `+`
to their strongly typed counterparts (`+!`, `+.`, `+$`, `+@`, `+$`) in
the translation to scopelang.
The patch includes some normalisation of the definition of all the
operators, and classifies them based on their typing policy instead of
their arity. It also adds a little more flexibility:
- a couple new operators, like `-` on date and duration
- optional type annotation on some aggregation constructions
The `Shared_ast` lib is also lightly restructured, with the `Expr`
module split into `Type`, `Operator` and `Expr`.
2022-11-29 11:47:53 +03:00
|
|
|
( EOp { op = Not; _ }, _
|
|
|
|
| ( EApp
|
|
|
|
{
|
|
|
|
f = EOp { op = Log _; _ }, _;
|
|
|
|
args = [(EOp { op = Not; _ }, _)];
|
|
|
|
},
|
2022-11-17 19:13:35 +03:00
|
|
|
_ ) ) as op;
|
|
|
|
args = [e1];
|
|
|
|
} -> (
|
|
|
|
(* reduction of logical not *)
|
|
|
|
match e1 with
|
|
|
|
| ELit (LBool false), _ -> ELit (LBool true)
|
|
|
|
| ELit (LBool true), _ -> ELit (LBool false)
|
|
|
|
| e1 -> EApp { f = op; args = [e1] })
|
|
|
|
| EApp
|
|
|
|
{
|
|
|
|
f =
|
Add overloaded operators for the common operations
This uses the same disambiguation mechanism put in place for
structures, calling the typer on individual rules on the desugared AST
to propagate types, in order to resolve ambiguous operators like `+`
to their strongly typed counterparts (`+!`, `+.`, `+$`, `+@`, `+$`) in
the translation to scopelang.
The patch includes some normalisation of the definition of all the
operators, and classifies them based on their typing policy instead of
their arity. It also adds a little more flexibility:
- a couple new operators, like `-` on date and duration
- optional type annotation on some aggregation constructions
The `Shared_ast` lib is also lightly restructured, with the `Expr`
module split into `Type`, `Operator` and `Expr`.
2022-11-29 11:47:53 +03:00
|
|
|
( EOp { op = Or; _ }, _
|
|
|
|
| ( EApp
|
|
|
|
{
|
|
|
|
f = EOp { op = Log _; _ }, _;
|
|
|
|
args = [(EOp { op = Or; _ }, _)];
|
|
|
|
},
|
2022-11-17 19:13:35 +03:00
|
|
|
_ ) ) as op;
|
|
|
|
args = [e1; e2];
|
|
|
|
} -> (
|
|
|
|
(* reduction of logical or *)
|
|
|
|
match e1, e2 with
|
|
|
|
| (ELit (LBool false), _), new_e | new_e, (ELit (LBool false), _) ->
|
|
|
|
Marked.unmark new_e
|
|
|
|
| (ELit (LBool true), _), _ | _, (ELit (LBool true), _) ->
|
|
|
|
ELit (LBool true)
|
|
|
|
| _ -> EApp { f = op; args = [e1; e2] })
|
|
|
|
| EApp
|
|
|
|
{
|
|
|
|
f =
|
Add overloaded operators for the common operations
This uses the same disambiguation mechanism put in place for
structures, calling the typer on individual rules on the desugared AST
to propagate types, in order to resolve ambiguous operators like `+`
to their strongly typed counterparts (`+!`, `+.`, `+$`, `+@`, `+$`) in
the translation to scopelang.
The patch includes some normalisation of the definition of all the
operators, and classifies them based on their typing policy instead of
their arity. It also adds a little more flexibility:
- a couple new operators, like `-` on date and duration
- optional type annotation on some aggregation constructions
The `Shared_ast` lib is also lightly restructured, with the `Expr`
module split into `Type`, `Operator` and `Expr`.
2022-11-29 11:47:53 +03:00
|
|
|
( EOp { op = And; _ }, _
|
|
|
|
| ( EApp
|
|
|
|
{
|
|
|
|
f = EOp { op = Log _; _ }, _;
|
|
|
|
args = [(EOp { op = And; _ }, _)];
|
|
|
|
},
|
2022-11-17 19:13:35 +03:00
|
|
|
_ ) ) as op;
|
|
|
|
args = [e1; e2];
|
|
|
|
} -> (
|
|
|
|
(* reduction of logical and *)
|
|
|
|
match e1, e2 with
|
|
|
|
| (ELit (LBool true), _), new_e | new_e, (ELit (LBool true), _) ->
|
|
|
|
Marked.unmark new_e
|
|
|
|
| (ELit (LBool false), _), _ | _, (ELit (LBool false), _) ->
|
|
|
|
ELit (LBool false)
|
|
|
|
| _ -> EApp { f = op; args = [e1; e2] })
|
|
|
|
| EMatch { e = EInj { e; name = name1; cons }, _; cases; name }
|
|
|
|
when EnumName.equal name name1 ->
|
|
|
|
(* iota reduction *)
|
2022-11-21 12:12:45 +03:00
|
|
|
EApp { f = EnumConstructor.Map.find cons cases; args = [e] }
|
2022-11-17 19:13:35 +03:00
|
|
|
| EApp { f = EAbs { binder; _ }, _; args } ->
|
|
|
|
(* beta reduction *)
|
|
|
|
Marked.unmark (Bindlib.msubst binder (List.map fst args |> Array.of_list))
|
2023-02-28 11:06:33 +03:00
|
|
|
| EStructAccess { name; field; e = EStruct { name = name1; fields }, _ }
|
|
|
|
when name = name1 ->
|
|
|
|
Marked.unmark (StructField.Map.find field fields)
|
2022-11-17 19:13:35 +03:00
|
|
|
| EDefault { excepts; just; cons } -> (
|
|
|
|
(* TODO: mechanically prove each of these optimizations correct :) *)
|
|
|
|
let excepts =
|
2023-03-30 19:53:07 +03:00
|
|
|
List.filter (fun except -> Marked.unmark except <> EEmptyError) excepts
|
2022-11-17 19:13:35 +03:00
|
|
|
(* we can discard the exceptions that are always empty error *)
|
|
|
|
in
|
|
|
|
let value_except_count =
|
|
|
|
List.fold_left
|
|
|
|
(fun nb except -> if Expr.is_value except then nb + 1 else nb)
|
|
|
|
0 excepts
|
|
|
|
in
|
|
|
|
if value_except_count > 1 then
|
|
|
|
(* at this point we know a conflict error will be triggered so we just
|
|
|
|
feed the expression to the interpreter that will print the beautiful
|
|
|
|
right error message *)
|
|
|
|
Marked.unmark (Interpreter.evaluate_expr ctx.decl_ctx e)
|
|
|
|
else
|
|
|
|
match excepts, just with
|
|
|
|
| [except], _ when Expr.is_value except ->
|
2022-01-09 21:16:34 +03:00
|
|
|
(* if there is only one exception and it is a non-empty value it is
|
|
|
|
always chosen *)
|
2022-11-17 19:13:35 +03:00
|
|
|
Marked.unmark except
|
2022-01-09 21:16:34 +03:00
|
|
|
| ( [],
|
|
|
|
( ( ELit (LBool true)
|
2022-11-17 19:13:35 +03:00
|
|
|
| EApp
|
Add overloaded operators for the common operations
This uses the same disambiguation mechanism put in place for
structures, calling the typer on individual rules on the desugared AST
to propagate types, in order to resolve ambiguous operators like `+`
to their strongly typed counterparts (`+!`, `+.`, `+$`, `+@`, `+$`) in
the translation to scopelang.
The patch includes some normalisation of the definition of all the
operators, and classifies them based on their typing policy instead of
their arity. It also adds a little more flexibility:
- a couple new operators, like `-` on date and duration
- optional type annotation on some aggregation constructions
The `Shared_ast` lib is also lightly restructured, with the `Expr`
module split into `Type`, `Operator` and `Expr`.
2022-11-29 11:47:53 +03:00
|
|
|
{
|
|
|
|
f = EOp { op = Log _; _ }, _;
|
|
|
|
args = [(ELit (LBool true), _)];
|
|
|
|
} ),
|
2022-11-17 19:13:35 +03:00
|
|
|
_ ) ) ->
|
|
|
|
Marked.unmark cons
|
2022-05-04 18:40:55 +03:00
|
|
|
| ( [],
|
2022-01-09 21:16:34 +03:00
|
|
|
( ( ELit (LBool false)
|
2022-11-17 19:13:35 +03:00
|
|
|
| EApp
|
|
|
|
{
|
Add overloaded operators for the common operations
This uses the same disambiguation mechanism put in place for
structures, calling the typer on individual rules on the desugared AST
to propagate types, in order to resolve ambiguous operators like `+`
to their strongly typed counterparts (`+!`, `+.`, `+$`, `+@`, `+$`) in
the translation to scopelang.
The patch includes some normalisation of the definition of all the
operators, and classifies them based on their typing policy instead of
their arity. It also adds a little more flexibility:
- a couple new operators, like `-` on date and duration
- optional type annotation on some aggregation constructions
The `Shared_ast` lib is also lightly restructured, with the `Expr`
module split into `Type`, `Operator` and `Expr`.
2022-11-29 11:47:53 +03:00
|
|
|
f = EOp { op = Log _; _ }, _;
|
2022-11-17 19:13:35 +03:00
|
|
|
args = [(ELit (LBool false), _)];
|
|
|
|
} ),
|
|
|
|
_ ) ) ->
|
2023-04-07 11:51:21 +03:00
|
|
|
EEmptyError
|
2023-04-03 11:56:44 +03:00
|
|
|
| [], just ->
|
2023-04-07 11:51:21 +03:00
|
|
|
EIfThenElse { cond = just; etrue = cons; efalse = EEmptyError, mark }
|
2022-11-17 19:13:35 +03:00
|
|
|
| excepts, just -> EDefault { excepts; just; cons })
|
|
|
|
| EIfThenElse
|
|
|
|
{
|
|
|
|
cond =
|
|
|
|
( ELit (LBool true), _
|
|
|
|
| ( EApp
|
Add overloaded operators for the common operations
This uses the same disambiguation mechanism put in place for
structures, calling the typer on individual rules on the desugared AST
to propagate types, in order to resolve ambiguous operators like `+`
to their strongly typed counterparts (`+!`, `+.`, `+$`, `+@`, `+$`) in
the translation to scopelang.
The patch includes some normalisation of the definition of all the
operators, and classifies them based on their typing policy instead of
their arity. It also adds a little more flexibility:
- a couple new operators, like `-` on date and duration
- optional type annotation on some aggregation constructions
The `Shared_ast` lib is also lightly restructured, with the `Expr`
module split into `Type`, `Operator` and `Expr`.
2022-11-29 11:47:53 +03:00
|
|
|
{
|
|
|
|
f = EOp { op = Log _; _ }, _;
|
|
|
|
args = [(ELit (LBool true), _)];
|
|
|
|
},
|
2022-11-17 19:13:35 +03:00
|
|
|
_ ) );
|
|
|
|
etrue;
|
|
|
|
_;
|
|
|
|
} ->
|
|
|
|
Marked.unmark etrue
|
|
|
|
| EIfThenElse
|
|
|
|
{
|
|
|
|
cond =
|
|
|
|
( ( ELit (LBool false)
|
|
|
|
| EApp
|
|
|
|
{
|
Add overloaded operators for the common operations
This uses the same disambiguation mechanism put in place for
structures, calling the typer on individual rules on the desugared AST
to propagate types, in order to resolve ambiguous operators like `+`
to their strongly typed counterparts (`+!`, `+.`, `+$`, `+@`, `+$`) in
the translation to scopelang.
The patch includes some normalisation of the definition of all the
operators, and classifies them based on their typing policy instead of
their arity. It also adds a little more flexibility:
- a couple new operators, like `-` on date and duration
- optional type annotation on some aggregation constructions
The `Shared_ast` lib is also lightly restructured, with the `Expr`
module split into `Type`, `Operator` and `Expr`.
2022-11-29 11:47:53 +03:00
|
|
|
f = EOp { op = Log _; _ }, _;
|
2022-11-17 19:13:35 +03:00
|
|
|
args = [(ELit (LBool false), _)];
|
|
|
|
} ),
|
|
|
|
_ );
|
|
|
|
efalse;
|
|
|
|
_;
|
|
|
|
} ->
|
|
|
|
Marked.unmark efalse
|
|
|
|
| EIfThenElse
|
|
|
|
{
|
|
|
|
cond;
|
|
|
|
etrue =
|
|
|
|
( ( ELit (LBool btrue)
|
|
|
|
| EApp
|
|
|
|
{
|
Add overloaded operators for the common operations
This uses the same disambiguation mechanism put in place for
structures, calling the typer on individual rules on the desugared AST
to propagate types, in order to resolve ambiguous operators like `+`
to their strongly typed counterparts (`+!`, `+.`, `+$`, `+@`, `+$`) in
the translation to scopelang.
The patch includes some normalisation of the definition of all the
operators, and classifies them based on their typing policy instead of
their arity. It also adds a little more flexibility:
- a couple new operators, like `-` on date and duration
- optional type annotation on some aggregation constructions
The `Shared_ast` lib is also lightly restructured, with the `Expr`
module split into `Type`, `Operator` and `Expr`.
2022-11-29 11:47:53 +03:00
|
|
|
f = EOp { op = Log _; _ }, _;
|
2022-11-17 19:13:35 +03:00
|
|
|
args = [(ELit (LBool btrue), _)];
|
|
|
|
} ),
|
|
|
|
_ );
|
|
|
|
efalse =
|
|
|
|
( ( ELit (LBool bfalse)
|
|
|
|
| EApp
|
|
|
|
{
|
Add overloaded operators for the common operations
This uses the same disambiguation mechanism put in place for
structures, calling the typer on individual rules on the desugared AST
to propagate types, in order to resolve ambiguous operators like `+`
to their strongly typed counterparts (`+!`, `+.`, `+$`, `+@`, `+$`) in
the translation to scopelang.
The patch includes some normalisation of the definition of all the
operators, and classifies them based on their typing policy instead of
their arity. It also adds a little more flexibility:
- a couple new operators, like `-` on date and duration
- optional type annotation on some aggregation constructions
The `Shared_ast` lib is also lightly restructured, with the `Expr`
module split into `Type`, `Operator` and `Expr`.
2022-11-29 11:47:53 +03:00
|
|
|
f = EOp { op = Log _; _ }, _;
|
2022-11-17 19:13:35 +03:00
|
|
|
args = [(ELit (LBool bfalse), _)];
|
|
|
|
} ),
|
|
|
|
_ );
|
|
|
|
} ->
|
|
|
|
if btrue && not bfalse then Marked.unmark cond
|
|
|
|
else if (not btrue) && bfalse then
|
Add overloaded operators for the common operations
This uses the same disambiguation mechanism put in place for
structures, calling the typer on individual rules on the desugared AST
to propagate types, in order to resolve ambiguous operators like `+`
to their strongly typed counterparts (`+!`, `+.`, `+$`, `+@`, `+$`) in
the translation to scopelang.
The patch includes some normalisation of the definition of all the
operators, and classifies them based on their typing policy instead of
their arity. It also adds a little more flexibility:
- a couple new operators, like `-` on date and duration
- optional type annotation on some aggregation constructions
The `Shared_ast` lib is also lightly restructured, with the `Expr`
module split into `Type`, `Operator` and `Expr`.
2022-11-29 11:47:53 +03:00
|
|
|
EApp
|
|
|
|
{
|
|
|
|
f = EOp { op = Not; tys = [TLit TBool, Expr.mark_pos mark] }, mark;
|
|
|
|
args = [cond];
|
|
|
|
}
|
2022-11-17 19:13:35 +03:00
|
|
|
(* note: this last call eliminates the condition & might skip log calls
|
|
|
|
as well *)
|
|
|
|
else (* btrue = bfalse *) ELit (LBool btrue)
|
|
|
|
| e -> e
|
|
|
|
in
|
|
|
|
Expr.Box.app1 e reduce mark
|
2022-01-07 20:36:56 +03:00
|
|
|
|
2022-08-25 17:35:08 +03:00
|
|
|
let optimize_expr (decl_ctx : decl_ctx) (e : 'm expr) =
|
2022-07-28 11:36:36 +03:00
|
|
|
partial_evaluation { var_values = Var.Map.empty; decl_ctx } e
|
2022-01-07 20:36:56 +03:00
|
|
|
|
2022-09-27 17:27:26 +03:00
|
|
|
let optimize_program (p : 'm program) : 'm program =
|
2022-04-02 15:51:11 +03:00
|
|
|
Bindlib.unbox
|
2023-01-23 14:19:36 +03:00
|
|
|
(Program.map_exprs
|
|
|
|
~f:
|
|
|
|
(partial_evaluation
|
|
|
|
{ var_values = Var.Map.empty; decl_ctx = p.decl_ctx })
|
|
|
|
~varf:(fun v -> v)
|
2022-04-02 15:51:11 +03:00
|
|
|
p)
|