2021-01-28 02:28:28 +03:00
|
|
|
(* This file is part of the Catala compiler, a specification language for tax
|
|
|
|
and social benefits computation rules. Copyright (C) 2020 Inria, contributor:
|
|
|
|
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. *)
|
|
|
|
|
|
|
|
open Utils
|
2022-08-12 18:59:49 +03:00
|
|
|
open Shared_ast
|
2021-01-28 02:28:28 +03:00
|
|
|
module D = Dcalc.Ast
|
|
|
|
module A = Ast
|
|
|
|
|
2022-08-25 20:46:13 +03:00
|
|
|
type 'm ctx = ('m D.expr, 'm A.expr Var.t) Var.Map.t
|
2021-12-10 01:29:49 +03:00
|
|
|
(** This environment contains a mapping between the variables in Dcalc and their
|
|
|
|
correspondance in Lcalc. *)
|
2021-01-28 02:28:28 +03:00
|
|
|
|
2022-09-12 18:03:44 +03:00
|
|
|
let thunk_expr (type m) (e : m A.expr Bindlib.box) : m A.expr Bindlib.box =
|
2022-07-28 11:36:36 +03:00
|
|
|
let dummy_var = Var.make "_" in
|
2022-09-12 18:03:44 +03:00
|
|
|
let pos = Expr.pos (Bindlib.unbox e) in
|
|
|
|
let arg_t = Marked.mark pos (TLit TUnit) in
|
|
|
|
Expr.make_abs [| dummy_var |] e [arg_t] pos
|
2021-01-28 20:30:01 +03:00
|
|
|
|
2021-01-28 02:28:28 +03:00
|
|
|
let rec translate_default
|
2022-06-23 15:06:11 +03:00
|
|
|
(ctx : 'm ctx)
|
2022-08-25 17:35:08 +03:00
|
|
|
(exceptions : 'm D.expr list)
|
|
|
|
(just : 'm D.expr)
|
|
|
|
(cons : 'm D.expr)
|
|
|
|
(mark_default : 'm mark) : 'm A.expr Bindlib.box =
|
2021-01-28 20:30:01 +03:00
|
|
|
let exceptions =
|
2022-09-12 18:03:44 +03:00
|
|
|
List.map (fun except -> thunk_expr (translate_expr ctx except)) exceptions
|
2021-01-28 20:30:01 +03:00
|
|
|
in
|
2021-01-28 02:28:28 +03:00
|
|
|
let exceptions =
|
2022-08-22 19:53:30 +03:00
|
|
|
Expr.make_app
|
|
|
|
(Expr.make_var (Var.translate A.handle_default, mark_default))
|
2021-01-28 02:28:28 +03:00
|
|
|
[
|
2022-08-12 23:42:39 +03:00
|
|
|
Expr.earray exceptions mark_default;
|
2022-09-12 18:03:44 +03:00
|
|
|
thunk_expr (translate_expr ctx just);
|
|
|
|
thunk_expr (translate_expr ctx cons);
|
2021-01-28 02:28:28 +03:00
|
|
|
]
|
2022-09-12 18:03:44 +03:00
|
|
|
(Expr.mark_pos mark_default)
|
2021-01-28 02:28:28 +03:00
|
|
|
in
|
|
|
|
exceptions
|
|
|
|
|
2022-08-25 20:46:13 +03:00
|
|
|
and translate_expr (ctx : 'm ctx) (e : 'm D.expr) : 'm A.expr Bindlib.box =
|
2022-05-30 12:20:48 +03:00
|
|
|
match Marked.unmark e with
|
2022-08-22 19:53:30 +03:00
|
|
|
| EVar v -> Expr.make_var (Var.Map.find v ctx, Marked.get_mark e)
|
2022-08-12 23:42:39 +03:00
|
|
|
| ETuple (args, s) ->
|
|
|
|
Expr.etuple (List.map (translate_expr ctx) args) s (Marked.get_mark e)
|
|
|
|
| ETupleAccess (e1, i, s, ts) ->
|
|
|
|
Expr.etupleaccess (translate_expr ctx e1) i s ts (Marked.get_mark e)
|
|
|
|
| EInj (e1, i, en, ts) ->
|
|
|
|
Expr.einj (translate_expr ctx e1) i en ts (Marked.get_mark e)
|
|
|
|
| EMatch (e1, cases, en) ->
|
|
|
|
Expr.ematch (translate_expr ctx e1)
|
2022-04-25 19:00:08 +03:00
|
|
|
(List.map (translate_expr ctx) cases)
|
2022-05-30 12:20:48 +03:00
|
|
|
en (Marked.get_mark e)
|
2022-08-12 23:42:39 +03:00
|
|
|
| EArray es ->
|
|
|
|
Expr.earray (List.map (translate_expr ctx) es) (Marked.get_mark e)
|
2022-08-25 13:09:51 +03:00
|
|
|
| ELit
|
|
|
|
((LBool _ | LInt _ | LRat _ | LMoney _ | LUnit | LDate _ | LDuration _) as
|
|
|
|
l) ->
|
|
|
|
Bindlib.box (Marked.same_mark_as (ELit l) e)
|
|
|
|
| ELit LEmptyError -> Bindlib.box (Marked.same_mark_as (ERaise EmptyError) e)
|
2022-08-12 23:42:39 +03:00
|
|
|
| EOp op -> Expr.eop op (Marked.get_mark e)
|
|
|
|
| EIfThenElse (e1, e2, e3) ->
|
|
|
|
Expr.eifthenelse (translate_expr ctx e1) (translate_expr ctx e2)
|
2022-05-30 12:20:48 +03:00
|
|
|
(translate_expr ctx e3) (Marked.get_mark e)
|
2022-08-12 23:42:39 +03:00
|
|
|
| EAssert e1 -> Expr.eassert (translate_expr ctx e1) (Marked.get_mark e)
|
|
|
|
| ErrorOnEmpty arg ->
|
|
|
|
Expr.ecatch (translate_expr ctx arg) EmptyError
|
|
|
|
(Bindlib.box (Marked.same_mark_as (ERaise NoValueProvided) e))
|
2022-05-30 12:20:48 +03:00
|
|
|
(Marked.get_mark e)
|
2022-08-12 23:42:39 +03:00
|
|
|
| EApp (e1, args) ->
|
|
|
|
Expr.eapp (translate_expr ctx e1)
|
2022-04-25 19:00:08 +03:00
|
|
|
(List.map (translate_expr ctx) args)
|
2022-05-30 12:20:48 +03:00
|
|
|
(Marked.get_mark e)
|
2022-08-12 23:42:39 +03:00
|
|
|
| EAbs (binder, ts) ->
|
2021-01-28 02:28:28 +03:00
|
|
|
let vars, body = Bindlib.unmbind binder in
|
|
|
|
let ctx, lc_vars =
|
|
|
|
Array.fold_right
|
|
|
|
(fun var (ctx, lc_vars) ->
|
2022-07-28 11:36:36 +03:00
|
|
|
let lc_var = Var.make (Bindlib.name_of var) in
|
|
|
|
Var.Map.add var lc_var ctx, lc_var :: lc_vars)
|
2021-01-28 02:28:28 +03:00
|
|
|
vars (ctx, [])
|
|
|
|
in
|
|
|
|
let lc_vars = Array.of_list lc_vars in
|
|
|
|
let new_body = translate_expr ctx body in
|
|
|
|
let new_binder = Bindlib.bind_mvar lc_vars new_body in
|
|
|
|
Bindlib.box_apply
|
2022-08-12 23:42:39 +03:00
|
|
|
(fun new_binder -> Marked.same_mark_as (EAbs (new_binder, ts)) e)
|
2021-01-28 02:28:28 +03:00
|
|
|
new_binder
|
2022-08-12 23:42:39 +03:00
|
|
|
| EDefault ([exn], just, cons) when !Cli.optimize_flag ->
|
|
|
|
Expr.ecatch (translate_expr ctx exn) EmptyError
|
|
|
|
(Expr.eifthenelse (translate_expr ctx just) (translate_expr ctx cons)
|
|
|
|
(Bindlib.box (Marked.same_mark_as (ERaise EmptyError) e))
|
2022-05-30 12:20:48 +03:00
|
|
|
(Marked.get_mark e))
|
|
|
|
(Marked.get_mark e)
|
2022-08-12 23:42:39 +03:00
|
|
|
| EDefault (exceptions, just, cons) ->
|
2022-05-30 12:20:48 +03:00
|
|
|
translate_default ctx exceptions just cons (Marked.get_mark e)
|
2021-01-28 02:28:28 +03:00
|
|
|
|
2022-04-25 19:00:08 +03:00
|
|
|
let rec translate_scope_lets
|
2022-08-12 23:42:39 +03:00
|
|
|
(decl_ctx : decl_ctx)
|
2022-06-23 15:06:11 +03:00
|
|
|
(ctx : 'm ctx)
|
2022-08-25 20:46:13 +03:00
|
|
|
(scope_lets : 'm D.expr scope_body_expr) :
|
|
|
|
'm A.expr scope_body_expr Bindlib.box =
|
2022-04-25 19:00:08 +03:00
|
|
|
match scope_lets with
|
2022-08-12 23:42:39 +03:00
|
|
|
| Result e -> Bindlib.box_apply (fun e -> Result e) (translate_expr ctx e)
|
2022-04-25 19:00:08 +03:00
|
|
|
| ScopeLet scope_let ->
|
|
|
|
let old_scope_let_var, scope_let_next =
|
|
|
|
Bindlib.unbind scope_let.scope_let_next
|
|
|
|
in
|
2022-07-28 11:36:36 +03:00
|
|
|
let new_scope_let_var = Var.make (Bindlib.name_of old_scope_let_var) in
|
2022-04-25 19:00:08 +03:00
|
|
|
let new_scope_let_expr = translate_expr ctx scope_let.scope_let_expr in
|
2022-07-28 11:36:36 +03:00
|
|
|
let new_ctx = Var.Map.add old_scope_let_var new_scope_let_var ctx in
|
2022-04-25 19:00:08 +03:00
|
|
|
let new_scope_next = translate_scope_lets decl_ctx new_ctx scope_let_next in
|
|
|
|
let new_scope_next = Bindlib.bind_var new_scope_let_var new_scope_next in
|
|
|
|
Bindlib.box_apply2
|
|
|
|
(fun new_scope_next new_scope_let_expr ->
|
2022-08-12 23:42:39 +03:00
|
|
|
ScopeLet
|
2022-04-25 19:00:08 +03:00
|
|
|
{
|
2022-08-12 23:42:39 +03:00
|
|
|
scope_let_typ = scope_let.scope_let_typ;
|
|
|
|
scope_let_kind = scope_let.scope_let_kind;
|
|
|
|
scope_let_pos = scope_let.scope_let_pos;
|
2022-04-25 19:00:08 +03:00
|
|
|
scope_let_next = new_scope_next;
|
|
|
|
scope_let_expr = new_scope_let_expr;
|
|
|
|
})
|
|
|
|
new_scope_next new_scope_let_expr
|
|
|
|
|
2022-04-02 15:51:11 +03:00
|
|
|
let rec translate_scopes
|
2022-08-12 23:42:39 +03:00
|
|
|
(decl_ctx : decl_ctx)
|
2022-06-23 15:06:11 +03:00
|
|
|
(ctx : 'm ctx)
|
2022-08-25 20:46:13 +03:00
|
|
|
(scopes : 'm D.expr scopes) : 'm A.expr scopes Bindlib.box =
|
2022-04-02 15:51:11 +03:00
|
|
|
match scopes with
|
2022-08-12 23:42:39 +03:00
|
|
|
| Nil -> Bindlib.box Nil
|
2022-04-02 15:51:11 +03:00
|
|
|
| ScopeDef scope_def ->
|
2022-04-25 19:00:08 +03:00
|
|
|
let old_scope_var, scope_next = Bindlib.unbind scope_def.scope_next in
|
|
|
|
let new_scope_var =
|
2022-08-12 23:42:39 +03:00
|
|
|
Var.make (Marked.unmark (ScopeName.get_info scope_def.scope_name))
|
2022-04-25 19:00:08 +03:00
|
|
|
in
|
|
|
|
let old_scope_input_var, scope_body_expr =
|
|
|
|
Bindlib.unbind scope_def.scope_body.scope_body_expr
|
|
|
|
in
|
2022-07-28 11:36:36 +03:00
|
|
|
let new_scope_input_var = Var.make (Bindlib.name_of old_scope_input_var) in
|
|
|
|
let new_ctx = Var.Map.add old_scope_input_var new_scope_input_var ctx in
|
2022-04-25 19:00:08 +03:00
|
|
|
let new_scope_body_expr =
|
|
|
|
translate_scope_lets decl_ctx new_ctx scope_body_expr
|
|
|
|
in
|
|
|
|
let new_scope_body_expr =
|
|
|
|
Bindlib.bind_var new_scope_input_var new_scope_body_expr
|
|
|
|
in
|
2022-08-25 20:46:13 +03:00
|
|
|
let new_scope : 'm A.expr scope_body Bindlib.box =
|
2022-04-25 19:00:08 +03:00
|
|
|
Bindlib.box_apply
|
|
|
|
(fun new_scope_body_expr ->
|
|
|
|
{
|
2022-08-12 23:42:39 +03:00
|
|
|
scope_body_input_struct =
|
2022-04-25 19:00:08 +03:00
|
|
|
scope_def.scope_body.scope_body_input_struct;
|
|
|
|
scope_body_output_struct =
|
|
|
|
scope_def.scope_body.scope_body_output_struct;
|
|
|
|
scope_body_expr = new_scope_body_expr;
|
|
|
|
})
|
|
|
|
new_scope_body_expr
|
|
|
|
in
|
2022-07-28 11:36:36 +03:00
|
|
|
let new_ctx = Var.Map.add old_scope_var new_scope_var new_ctx in
|
2022-04-25 19:00:08 +03:00
|
|
|
let scope_next =
|
|
|
|
Bindlib.bind_var new_scope_var
|
|
|
|
(translate_scopes decl_ctx new_ctx scope_next)
|
|
|
|
in
|
|
|
|
Bindlib.box_apply2
|
|
|
|
(fun new_scope scope_next ->
|
2022-08-12 23:42:39 +03:00
|
|
|
ScopeDef
|
2022-04-25 19:00:08 +03:00
|
|
|
{
|
|
|
|
scope_name = scope_def.scope_name;
|
|
|
|
scope_body = new_scope;
|
|
|
|
scope_next;
|
|
|
|
})
|
|
|
|
new_scope scope_next
|
2022-04-02 15:51:11 +03:00
|
|
|
|
2022-06-23 15:06:11 +03:00
|
|
|
let translate_program (prgm : 'm D.program) : 'm A.program =
|
2021-01-28 15:58:59 +03:00
|
|
|
{
|
2022-04-25 19:00:08 +03:00
|
|
|
scopes =
|
2022-07-28 11:36:36 +03:00
|
|
|
Bindlib.unbox (translate_scopes prgm.decl_ctx Var.Map.empty prgm.scopes);
|
2021-01-29 13:42:19 +03:00
|
|
|
decl_ctx = prgm.decl_ctx;
|
2021-01-28 15:58:59 +03:00
|
|
|
}
|