2021-01-26 12:08:18 +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
|
|
|
|
module D = Dcalc.Ast
|
|
|
|
|
|
|
|
type lit =
|
|
|
|
| LBool of bool
|
2021-03-05 21:16:56 +03:00
|
|
|
| LInt of Runtime.integer
|
|
|
|
| LRat of Runtime.decimal
|
|
|
|
| LMoney of Runtime.money
|
2021-01-26 12:08:18 +03:00
|
|
|
| LUnit
|
2021-03-05 21:16:56 +03:00
|
|
|
| LDate of Runtime.date
|
|
|
|
| LDuration of Runtime.duration
|
2021-01-26 12:08:18 +03:00
|
|
|
|
2022-02-18 17:47:54 +03:00
|
|
|
type except = ConflictError | EmptyError | NoValueProvided | Crash
|
2022-01-25 15:55:17 +03:00
|
|
|
|
2022-06-03 17:40:03 +03:00
|
|
|
type marked_expr = expr Marked.pos
|
|
|
|
|
|
|
|
and expr =
|
|
|
|
| EVar of expr Bindlib.var
|
|
|
|
| ETuple of marked_expr list * D.StructName.t option
|
2021-01-26 12:08:18 +03:00
|
|
|
(** The [MarkedString.info] is the former struct field name*)
|
2022-02-04 14:28:03 +03:00
|
|
|
| ETupleAccess of
|
2022-06-03 17:40:03 +03:00
|
|
|
marked_expr * int * D.StructName.t option * D.typ Marked.pos list
|
2021-01-26 12:08:18 +03:00
|
|
|
(** The [MarkedString.info] is the former struct field name *)
|
2022-06-03 17:40:03 +03:00
|
|
|
| EInj of marked_expr * int * D.EnumName.t * D.typ Marked.pos list
|
2021-01-26 12:08:18 +03:00
|
|
|
(** The [MarkedString.info] is the former enum case name *)
|
2022-06-03 17:40:03 +03:00
|
|
|
| EMatch of marked_expr * marked_expr list * D.EnumName.t
|
2021-01-26 12:08:18 +03:00
|
|
|
(** The [MarkedString.info] is the former enum case name *)
|
2022-06-03 17:40:03 +03:00
|
|
|
| EArray of marked_expr list
|
2022-02-04 14:28:03 +03:00
|
|
|
| ELit of lit
|
2022-06-03 17:40:03 +03:00
|
|
|
| EAbs of (expr, marked_expr) Bindlib.mbinder * D.typ Marked.pos list
|
|
|
|
| EApp of marked_expr * marked_expr list
|
|
|
|
| EAssert of marked_expr
|
2021-01-26 12:08:18 +03:00
|
|
|
| EOp of D.operator
|
2022-06-03 17:40:03 +03:00
|
|
|
| EIfThenElse of marked_expr * marked_expr * marked_expr
|
2021-01-28 02:28:28 +03:00
|
|
|
| ERaise of except
|
2022-06-03 17:40:03 +03:00
|
|
|
| ECatch of marked_expr * except * marked_expr
|
2022-02-04 14:28:03 +03:00
|
|
|
|
2022-04-15 13:16:44 +03:00
|
|
|
type program = { decl_ctx : Dcalc.Ast.decl_ctx; scopes : expr Dcalc.Ast.scopes }
|
2022-04-12 18:54:00 +03:00
|
|
|
|
2022-05-30 12:20:48 +03:00
|
|
|
let evar (v : expr Bindlib.var) (pos : Pos.t) : expr Marked.pos Bindlib.box =
|
2022-04-15 13:16:44 +03:00
|
|
|
Bindlib.box_apply (fun v' -> v', pos) (Bindlib.box_var v)
|
|
|
|
|
|
|
|
let etuple
|
2022-05-30 12:20:48 +03:00
|
|
|
(args : expr Marked.pos Bindlib.box list)
|
2022-04-15 13:16:44 +03:00
|
|
|
(s : Dcalc.Ast.StructName.t option)
|
2022-05-30 12:20:48 +03:00
|
|
|
(pos : Pos.t) : expr Marked.pos Bindlib.box =
|
2022-04-15 13:16:44 +03:00
|
|
|
Bindlib.box_apply (fun args -> ETuple (args, s), pos) (Bindlib.box_list args)
|
|
|
|
|
|
|
|
let etupleaccess
|
2022-05-30 12:20:48 +03:00
|
|
|
(e1 : expr Marked.pos Bindlib.box)
|
2022-04-15 13:16:44 +03:00
|
|
|
(i : int)
|
|
|
|
(s : Dcalc.Ast.StructName.t option)
|
2022-05-30 12:20:48 +03:00
|
|
|
(typs : Dcalc.Ast.typ Marked.pos list)
|
|
|
|
(pos : Pos.t) : expr Marked.pos Bindlib.box =
|
2022-04-15 13:16:44 +03:00
|
|
|
Bindlib.box_apply (fun e1 -> ETupleAccess (e1, i, s, typs), pos) e1
|
|
|
|
|
|
|
|
let einj
|
2022-05-30 12:20:48 +03:00
|
|
|
(e1 : expr Marked.pos Bindlib.box)
|
2022-04-15 13:16:44 +03:00
|
|
|
(i : int)
|
|
|
|
(e_name : Dcalc.Ast.EnumName.t)
|
2022-05-30 12:20:48 +03:00
|
|
|
(typs : Dcalc.Ast.typ Marked.pos list)
|
|
|
|
(pos : Pos.t) : expr Marked.pos Bindlib.box =
|
2022-04-15 13:16:44 +03:00
|
|
|
Bindlib.box_apply (fun e1 -> EInj (e1, i, e_name, typs), pos) e1
|
|
|
|
|
|
|
|
let ematch
|
2022-05-30 12:20:48 +03:00
|
|
|
(arg : expr Marked.pos Bindlib.box)
|
|
|
|
(arms : expr Marked.pos Bindlib.box list)
|
2022-04-15 13:16:44 +03:00
|
|
|
(e_name : Dcalc.Ast.EnumName.t)
|
2022-05-30 12:20:48 +03:00
|
|
|
(pos : Pos.t) : expr Marked.pos Bindlib.box =
|
2022-04-15 13:16:44 +03:00
|
|
|
Bindlib.box_apply2
|
|
|
|
(fun arg arms -> EMatch (arg, arms, e_name), pos)
|
|
|
|
arg (Bindlib.box_list arms)
|
|
|
|
|
2022-05-30 12:20:48 +03:00
|
|
|
let earray (args : expr Marked.pos Bindlib.box list) (pos : Pos.t) :
|
|
|
|
expr Marked.pos Bindlib.box =
|
2022-04-15 13:16:44 +03:00
|
|
|
Bindlib.box_apply (fun args -> EArray args, pos) (Bindlib.box_list args)
|
|
|
|
|
2022-05-30 12:20:48 +03:00
|
|
|
let elit (l : lit) (pos : Pos.t) : expr Marked.pos Bindlib.box =
|
2022-04-15 13:16:44 +03:00
|
|
|
Bindlib.box (ELit l, pos)
|
|
|
|
|
|
|
|
let eabs
|
2022-05-30 12:20:48 +03:00
|
|
|
(binder : (expr, expr Marked.pos) Bindlib.mbinder Bindlib.box)
|
|
|
|
(typs : Dcalc.Ast.typ Marked.pos list)
|
|
|
|
(pos : Pos.t) : expr Marked.pos Bindlib.box =
|
2022-06-03 17:40:03 +03:00
|
|
|
Bindlib.box_apply (fun binder -> EAbs (binder, typs), pos) binder
|
2022-04-15 13:16:44 +03:00
|
|
|
|
|
|
|
let eapp
|
2022-05-30 12:20:48 +03:00
|
|
|
(e1 : expr Marked.pos Bindlib.box)
|
|
|
|
(args : expr Marked.pos Bindlib.box list)
|
|
|
|
(pos : Pos.t) : expr Marked.pos Bindlib.box =
|
2022-04-15 13:16:44 +03:00
|
|
|
Bindlib.box_apply2
|
|
|
|
(fun e1 args -> EApp (e1, args), pos)
|
|
|
|
e1 (Bindlib.box_list args)
|
|
|
|
|
2022-05-30 12:20:48 +03:00
|
|
|
let eassert (e1 : expr Marked.pos Bindlib.box) (pos : Pos.t) :
|
|
|
|
expr Marked.pos Bindlib.box =
|
2022-04-15 13:16:44 +03:00
|
|
|
Bindlib.box_apply (fun e1 -> EAssert e1, pos) e1
|
|
|
|
|
2022-05-30 12:20:48 +03:00
|
|
|
let eop (op : Dcalc.Ast.operator) (pos : Pos.t) : expr Marked.pos Bindlib.box =
|
2022-04-15 13:16:44 +03:00
|
|
|
Bindlib.box (EOp op, pos)
|
|
|
|
|
2022-05-30 12:20:48 +03:00
|
|
|
let eraise (e1 : except) (pos : Pos.t) : expr Marked.pos Bindlib.box =
|
2022-04-15 13:16:44 +03:00
|
|
|
Bindlib.box (ERaise e1, pos)
|
|
|
|
|
|
|
|
let ecatch
|
2022-05-30 12:20:48 +03:00
|
|
|
(e1 : expr Marked.pos Bindlib.box)
|
2022-04-15 13:16:44 +03:00
|
|
|
(exn : except)
|
2022-05-30 12:20:48 +03:00
|
|
|
(e2 : expr Marked.pos Bindlib.box)
|
|
|
|
(pos : Pos.t) : expr Marked.pos Bindlib.box =
|
2022-04-15 13:16:44 +03:00
|
|
|
Bindlib.box_apply2 (fun e1 e2 -> ECatch (e1, exn, e2), pos) e1 e2
|
|
|
|
|
|
|
|
let eifthenelse
|
2022-05-30 12:20:48 +03:00
|
|
|
(e1 : expr Marked.pos Bindlib.box)
|
|
|
|
(e2 : expr Marked.pos Bindlib.box)
|
|
|
|
(e3 : expr Marked.pos Bindlib.box)
|
|
|
|
(pos : Pos.t) : expr Marked.pos Bindlib.box =
|
2022-04-15 13:16:44 +03:00
|
|
|
Bindlib.box_apply3 (fun e1 e2 e3 -> EIfThenElse (e1, e2, e3), pos) e1 e2 e3
|
2022-04-12 18:54:00 +03:00
|
|
|
|
2021-01-26 12:08:18 +03:00
|
|
|
module Var = struct
|
|
|
|
type t = expr Bindlib.var
|
|
|
|
|
2022-06-03 17:40:03 +03:00
|
|
|
let make (s : string) : t =
|
|
|
|
Bindlib.new_var (fun (x : expr Bindlib.var) : expr -> EVar x) s
|
2021-01-26 12:08:18 +03:00
|
|
|
|
|
|
|
let compare x y = Bindlib.compare_vars x y
|
|
|
|
end
|
|
|
|
|
|
|
|
module VarMap = Map.Make (Var)
|
2022-03-21 19:26:23 +03:00
|
|
|
module VarSet = Set.Make (Var)
|
2021-01-26 12:08:18 +03:00
|
|
|
|
|
|
|
type vars = expr Bindlib.mvar
|
|
|
|
|
2022-04-15 13:16:44 +03:00
|
|
|
let map_expr
|
|
|
|
(ctx : 'a)
|
2022-05-30 12:20:48 +03:00
|
|
|
~(f : 'a -> expr Marked.pos -> expr Marked.pos Bindlib.box)
|
|
|
|
(e : expr Marked.pos) : expr Marked.pos Bindlib.box =
|
|
|
|
match Marked.unmark e with
|
2022-06-03 17:40:03 +03:00
|
|
|
| EVar v -> evar v (Marked.get_mark e)
|
2022-04-15 13:16:44 +03:00
|
|
|
| EApp (e1, args) ->
|
2022-05-30 12:20:48 +03:00
|
|
|
eapp (f ctx e1) (List.map (f ctx) args) (Marked.get_mark e)
|
2022-06-03 17:40:03 +03:00
|
|
|
| EAbs (binder, typs) ->
|
|
|
|
eabs (Bindlib.box_mbinder (f ctx) binder) typs (Marked.get_mark e)
|
2022-05-30 12:20:48 +03:00
|
|
|
| ETuple (args, s) -> etuple (List.map (f ctx) args) s (Marked.get_mark e)
|
2022-04-15 13:16:44 +03:00
|
|
|
| ETupleAccess (e1, n, s_name, typs) ->
|
2022-05-30 12:20:48 +03:00
|
|
|
etupleaccess ((f ctx) e1) n s_name typs (Marked.get_mark e)
|
2022-04-15 13:16:44 +03:00
|
|
|
| EInj (e1, i, e_name, typs) ->
|
2022-05-30 12:20:48 +03:00
|
|
|
einj ((f ctx) e1) i e_name typs (Marked.get_mark e)
|
2022-04-15 13:16:44 +03:00
|
|
|
| EMatch (arg, arms, e_name) ->
|
2022-05-30 12:20:48 +03:00
|
|
|
ematch ((f ctx) arg) (List.map (f ctx) arms) e_name (Marked.get_mark e)
|
|
|
|
| EArray args -> earray (List.map (f ctx) args) (Marked.get_mark e)
|
|
|
|
| ELit l -> elit l (Marked.get_mark e)
|
|
|
|
| EAssert e1 -> eassert ((f ctx) e1) (Marked.get_mark e)
|
|
|
|
| EOp op -> Bindlib.box (EOp op, Marked.get_mark e)
|
|
|
|
| ERaise exn -> eraise exn (Marked.get_mark e)
|
2022-04-15 13:16:44 +03:00
|
|
|
| EIfThenElse (e1, e2, e3) ->
|
2022-05-30 12:20:48 +03:00
|
|
|
eifthenelse ((f ctx) e1) ((f ctx) e2) ((f ctx) e3) (Marked.get_mark e)
|
|
|
|
| ECatch (e1, exn, e2) -> ecatch (f ctx e1) exn (f ctx e2) (Marked.get_mark e)
|
2022-04-15 13:16:44 +03:00
|
|
|
|
|
|
|
(** See [Bindlib.box_term] documentation for why we are doing that. *)
|
2022-05-30 12:20:48 +03:00
|
|
|
let box_expr (e : expr Marked.pos) : expr Marked.pos Bindlib.box =
|
2022-04-15 13:16:44 +03:00
|
|
|
let rec id_t () e = map_expr () ~f:id_t e in
|
|
|
|
id_t () e
|
|
|
|
|
2022-05-30 12:20:48 +03:00
|
|
|
let make_var ((x, pos) : Var.t Marked.pos) : expr Marked.pos Bindlib.box =
|
2021-01-26 12:08:18 +03:00
|
|
|
Bindlib.box_apply (fun x -> x, pos) (Bindlib.box_var x)
|
|
|
|
|
|
|
|
let make_abs
|
|
|
|
(xs : vars)
|
2022-05-30 12:20:48 +03:00
|
|
|
(e : expr Marked.pos Bindlib.box)
|
|
|
|
(taus : D.typ Marked.pos list)
|
|
|
|
(pos : Pos.t) : expr Marked.pos Bindlib.box =
|
2022-06-03 17:40:03 +03:00
|
|
|
Bindlib.box_apply (fun b -> EAbs (b, taus), pos) (Bindlib.bind_mvar xs e)
|
2022-03-08 17:03:14 +03:00
|
|
|
|
2021-01-26 12:08:18 +03:00
|
|
|
let make_app
|
2022-05-30 12:20:48 +03:00
|
|
|
(e : expr Marked.pos Bindlib.box)
|
|
|
|
(u : expr Marked.pos Bindlib.box list)
|
|
|
|
(pos : Pos.t) : expr Marked.pos Bindlib.box =
|
2021-01-26 12:08:18 +03:00
|
|
|
Bindlib.box_apply2 (fun e u -> EApp (e, u), pos) e (Bindlib.box_list u)
|
|
|
|
|
|
|
|
let make_let_in
|
|
|
|
(x : Var.t)
|
2022-05-30 12:20:48 +03:00
|
|
|
(tau : D.typ Marked.pos)
|
|
|
|
(e1 : expr Marked.pos Bindlib.box)
|
|
|
|
(e2 : expr Marked.pos Bindlib.box)
|
|
|
|
(pos : Pos.t) : expr Marked.pos Bindlib.box =
|
2022-06-03 17:40:03 +03:00
|
|
|
make_app (make_abs (Array.of_list [x]) e2 [tau] pos) [e1] pos
|
2021-11-04 19:57:41 +03:00
|
|
|
|
2022-03-31 13:19:31 +03:00
|
|
|
let make_multiple_let_in
|
|
|
|
(xs : Var.t array)
|
2022-05-30 12:20:48 +03:00
|
|
|
(taus : D.typ Marked.pos list)
|
|
|
|
(e1 : expr Marked.pos Bindlib.box list)
|
|
|
|
(e2 : expr Marked.pos Bindlib.box)
|
|
|
|
(pos : Pos.t) : expr Marked.pos Bindlib.box =
|
2022-06-03 17:40:03 +03:00
|
|
|
make_app (make_abs xs e2 taus pos) e1 pos
|
2022-03-31 13:19:31 +03:00
|
|
|
|
2021-11-25 20:55:23 +03:00
|
|
|
let ( let+ ) x f = Bindlib.box_apply f x
|
|
|
|
let ( and+ ) x y = Bindlib.box_pair x y
|
2021-11-26 19:10:31 +03:00
|
|
|
let option_enum : D.EnumName.t = D.EnumName.fresh ("eoption", Pos.no_pos)
|
2021-11-04 19:57:41 +03:00
|
|
|
|
2021-11-26 19:10:31 +03:00
|
|
|
let none_constr : D.EnumConstructor.t =
|
|
|
|
D.EnumConstructor.fresh ("ENone", Pos.no_pos)
|
2021-11-25 19:24:18 +03:00
|
|
|
|
2021-11-26 19:10:31 +03:00
|
|
|
let some_constr : D.EnumConstructor.t =
|
|
|
|
D.EnumConstructor.fresh ("ESome", Pos.no_pos)
|
|
|
|
|
2022-05-30 12:20:48 +03:00
|
|
|
let option_enum_config : (D.EnumConstructor.t * D.typ Marked.pos) list =
|
2021-11-26 19:10:31 +03:00
|
|
|
[none_constr, (D.TLit D.TUnit, Pos.no_pos); some_constr, (D.TAny, Pos.no_pos)]
|
|
|
|
|
2022-05-30 12:20:48 +03:00
|
|
|
let make_none (pos : Pos.t) : expr Marked.pos Bindlib.box =
|
|
|
|
let mark : 'a -> 'a Marked.pos = Marked.mark pos in
|
2022-02-24 18:49:18 +03:00
|
|
|
Bindlib.box @@ mark
|
|
|
|
@@ EInj
|
|
|
|
(mark @@ ELit LUnit, 0, option_enum, [D.TLit D.TUnit, pos; D.TAny, pos])
|
2021-11-25 19:24:18 +03:00
|
|
|
|
2022-05-30 12:20:48 +03:00
|
|
|
let make_some (e : expr Marked.pos Bindlib.box) : expr Marked.pos Bindlib.box =
|
|
|
|
let pos = Marked.get_mark @@ Bindlib.unbox e in
|
|
|
|
let mark : 'a -> 'a Marked.pos = Marked.mark pos in
|
2022-03-08 18:13:47 +03:00
|
|
|
begin[@ocamlformat "disable"]
|
|
|
|
let+ e = e in
|
2022-02-24 18:49:18 +03:00
|
|
|
mark @@ EInj (e, 1, option_enum, [ (D.TLit D.TUnit, pos); (D.TAny, pos) ])
|
2022-05-04 19:38:28 +03:00
|
|
|
end
|
2021-11-25 19:24:18 +03:00
|
|
|
|
2022-02-04 14:28:03 +03:00
|
|
|
(** [make_matchopt_with_abs_arms arg e_none e_some] build an expression
|
|
|
|
[match arg with |None -> e_none | Some -> e_some] and requires e_some and
|
|
|
|
e_none to be in the form [EAbs ...].*)
|
|
|
|
let make_matchopt_with_abs_arms
|
2022-05-30 12:20:48 +03:00
|
|
|
(arg : expr Marked.pos Bindlib.box)
|
|
|
|
(e_none : expr Marked.pos Bindlib.box)
|
|
|
|
(e_some : expr Marked.pos Bindlib.box) : expr Marked.pos Bindlib.box =
|
|
|
|
let pos = Marked.get_mark @@ Bindlib.unbox arg in
|
|
|
|
let mark : 'a -> 'a Marked.pos = Marked.mark pos in
|
2022-03-15 20:02:08 +03:00
|
|
|
begin[@ocamlformat "disable"]
|
|
|
|
let+ arg = arg
|
|
|
|
and+ e_none = e_none
|
|
|
|
and+ e_some = e_some in
|
2022-02-02 14:23:52 +03:00
|
|
|
mark @@ EMatch (arg, [ e_none; e_some ], option_enum)
|
2022-05-04 19:38:28 +03:00
|
|
|
end
|
2021-11-30 20:05:30 +03:00
|
|
|
|
2022-02-04 14:28:03 +03:00
|
|
|
(** [make_matchopt pos v tau arg e_none e_some] builds an expression
|
|
|
|
[match arg with | None () -> e_none | Some v -> e_some]. It binds v to
|
|
|
|
e_some, permitting it to be used inside the expression. There is no
|
|
|
|
requirements on the form of both e_some and e_none. *)
|
2022-02-02 14:23:52 +03:00
|
|
|
let make_matchopt
|
|
|
|
(pos : Pos.t)
|
|
|
|
(v : Var.t)
|
2022-05-30 12:20:48 +03:00
|
|
|
(tau : D.typ Marked.pos)
|
|
|
|
(arg : expr Marked.pos Bindlib.box)
|
|
|
|
(e_none : expr Marked.pos Bindlib.box)
|
|
|
|
(e_some : expr Marked.pos Bindlib.box) : expr Marked.pos Bindlib.box =
|
2022-06-03 17:40:03 +03:00
|
|
|
let x = Var.make "_" in
|
2021-12-07 20:56:10 +03:00
|
|
|
|
2022-02-04 14:28:03 +03:00
|
|
|
make_matchopt_with_abs_arms arg
|
2022-06-03 17:40:03 +03:00
|
|
|
(make_abs (Array.of_list [x]) e_none [D.TLit D.TUnit, pos] pos)
|
|
|
|
(make_abs (Array.of_list [v]) e_some [tau] pos)
|
2021-12-07 20:56:10 +03:00
|
|
|
|
2022-06-03 17:40:03 +03:00
|
|
|
let handle_default = Var.make "handle_default"
|
|
|
|
let handle_default_opt = Var.make "handle_default_opt"
|
2021-12-07 18:03:15 +03:00
|
|
|
|
2022-05-30 12:20:48 +03:00
|
|
|
type binder = (expr, expr Marked.pos) Bindlib.binder
|