package catala

  1. Overview
  2. Docs
Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source

Source file compile_with_exceptions.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
(* 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
module D = Dcalc.Ast
module A = Ast

type 'm ctx = 'm A.var D.VarMap.t
(** This environment contains a mapping between the variables in Dcalc and their
    correspondance in Lcalc. *)

let translate_lit (l : D.lit) : 'm A.expr =
  match l with
  | D.LBool l -> A.ELit (A.LBool l)
  | D.LInt i -> A.ELit (A.LInt i)
  | D.LRat r -> A.ELit (A.LRat r)
  | D.LMoney m -> A.ELit (A.LMoney m)
  | D.LUnit -> A.ELit A.LUnit
  | D.LDate d -> A.ELit (A.LDate d)
  | D.LDuration d -> A.ELit (A.LDuration d)
  | D.LEmptyError -> A.ERaise A.EmptyError

let thunk_expr (e : 'm A.marked_expr Bindlib.box) (mark : 'm A.mark) :
    'm A.marked_expr Bindlib.box =
  let dummy_var = A.new_var "_" in
  A.make_abs [| dummy_var |] e [D.TAny, D.mark_pos mark] mark

let rec translate_default
    (ctx : 'm ctx)
    (exceptions : 'm D.marked_expr list)
    (just : 'm D.marked_expr)
    (cons : 'm D.marked_expr)
    (mark_default : 'm D.mark) : 'm A.marked_expr Bindlib.box =
  let exceptions =
    List.map
      (fun except -> thunk_expr (translate_expr ctx except) mark_default)
      exceptions
  in
  let exceptions =
    A.make_app
      (A.make_var (A.Var.get A.handle_default, mark_default))
      [
        A.earray exceptions mark_default;
        thunk_expr (translate_expr ctx just) mark_default;
        thunk_expr (translate_expr ctx cons) mark_default;
      ]
      mark_default
  in
  exceptions

and translate_expr (ctx : 'm ctx) (e : 'm D.marked_expr) :
    'm A.marked_expr Bindlib.box =
  match Marked.unmark e with
  | D.EVar v -> A.make_var (D.VarMap.find (D.Var.t v) ctx, Marked.get_mark e)
  | D.ETuple (args, s) ->
    A.etuple (List.map (translate_expr ctx) args) s (Marked.get_mark e)
  | D.ETupleAccess (e1, i, s, ts) ->
    A.etupleaccess (translate_expr ctx e1) i s ts (Marked.get_mark e)
  | D.EInj (e1, i, en, ts) ->
    A.einj (translate_expr ctx e1) i en ts (Marked.get_mark e)
  | D.EMatch (e1, cases, en) ->
    A.ematch (translate_expr ctx e1)
      (List.map (translate_expr ctx) cases)
      en (Marked.get_mark e)
  | D.EArray es ->
    A.earray (List.map (translate_expr ctx) es) (Marked.get_mark e)
  | D.ELit l -> Bindlib.box (Marked.same_mark_as (translate_lit l) e)
  | D.EOp op -> A.eop op (Marked.get_mark e)
  | D.EIfThenElse (e1, e2, e3) ->
    A.eifthenelse (translate_expr ctx e1) (translate_expr ctx e2)
      (translate_expr ctx e3) (Marked.get_mark e)
  | D.EAssert e1 -> A.eassert (translate_expr ctx e1) (Marked.get_mark e)
  | D.ErrorOnEmpty arg ->
    A.ecatch (translate_expr ctx arg) A.EmptyError
      (Bindlib.box (Marked.same_mark_as (A.ERaise A.NoValueProvided) e))
      (Marked.get_mark e)
  | D.EApp (e1, args) ->
    A.eapp (translate_expr ctx e1)
      (List.map (translate_expr ctx) args)
      (Marked.get_mark e)
  | D.EAbs (binder, ts) ->
    let vars, body = Bindlib.unmbind binder in
    let ctx, lc_vars =
      Array.fold_right
        (fun var (ctx, lc_vars) ->
          let lc_var = A.new_var (Bindlib.name_of var) in
          D.VarMap.add (D.Var.t var) lc_var ctx, lc_var :: lc_vars)
        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
      (fun new_binder -> Marked.same_mark_as (A.EAbs (new_binder, ts)) e)
      new_binder
  | D.EDefault ([exn], just, cons) when !Cli.optimize_flag ->
    A.ecatch (translate_expr ctx exn) A.EmptyError
      (A.eifthenelse (translate_expr ctx just) (translate_expr ctx cons)
         (Bindlib.box (Marked.same_mark_as (A.ERaise A.EmptyError) e))
         (Marked.get_mark e))
      (Marked.get_mark e)
  | D.EDefault (exceptions, just, cons) ->
    translate_default ctx exceptions just cons (Marked.get_mark e)

let rec translate_scope_lets
    (decl_ctx : D.decl_ctx)
    (ctx : 'm ctx)
    (scope_lets : ('m D.expr, 'm) D.scope_body_expr) :
    ('m A.expr, 'm) D.scope_body_expr Bindlib.box =
  match scope_lets with
  | Result e -> Bindlib.box_apply (fun e -> D.Result e) (translate_expr ctx e)
  | ScopeLet scope_let ->
    let old_scope_let_var, scope_let_next =
      Bindlib.unbind scope_let.scope_let_next
    in
    let new_scope_let_var = A.new_var (Bindlib.name_of old_scope_let_var) in
    let new_scope_let_expr = translate_expr ctx scope_let.scope_let_expr in
    let new_ctx =
      D.VarMap.add (D.Var.t old_scope_let_var) new_scope_let_var ctx
    in
    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 ->
        D.ScopeLet
          {
            scope_let_typ = scope_let.D.scope_let_typ;
            scope_let_kind = scope_let.D.scope_let_kind;
            scope_let_pos = scope_let.D.scope_let_pos;
            scope_let_next = new_scope_next;
            scope_let_expr = new_scope_let_expr;
          })
      new_scope_next new_scope_let_expr

let rec translate_scopes
    (decl_ctx : D.decl_ctx)
    (ctx : 'm ctx)
    (scopes : ('m D.expr, 'm) D.scopes) : ('m A.expr, 'm) D.scopes Bindlib.box =
  match scopes with
  | Nil -> Bindlib.box D.Nil
  | ScopeDef scope_def ->
    let old_scope_var, scope_next = Bindlib.unbind scope_def.scope_next in
    let new_scope_var =
      A.new_var (Marked.unmark (D.ScopeName.get_info scope_def.scope_name))
    in
    let old_scope_input_var, scope_body_expr =
      Bindlib.unbind scope_def.scope_body.scope_body_expr
    in
    let new_scope_input_var = A.new_var (Bindlib.name_of old_scope_input_var) in
    let new_ctx =
      D.VarMap.add (D.Var.t old_scope_input_var) new_scope_input_var ctx
    in
    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
    let new_scope : ('m A.expr, 'm) D.scope_body Bindlib.box =
      Bindlib.box_apply
        (fun new_scope_body_expr ->
          {
            D.scope_body_input_struct =
              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
    let new_ctx = D.VarMap.add (D.Var.t old_scope_var) new_scope_var new_ctx in
    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 ->
        D.ScopeDef
          {
            scope_name = scope_def.scope_name;
            scope_body = new_scope;
            scope_next;
          })
      new_scope scope_next

let translate_program (prgm : 'm D.program) : 'm A.program =
  {
    scopes =
      Bindlib.unbox (translate_scopes prgm.decl_ctx D.VarMap.empty prgm.scopes);
    decl_ctx = prgm.decl_ctx;
  }
OCaml

Innovation. Community. Security.