2022-03-08 17:03:14 +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>
|
2020-11-23 18:12:45 +03:00
|
|
|
|
2022-03-08 17:03:14 +03:00
|
|
|
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
|
2020-11-23 18:12:45 +03:00
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
2022-03-08 17:03:14 +03:00
|
|
|
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
|
2020-11-23 18:12:45 +03:00
|
|
|
the License. *)
|
|
|
|
|
2021-01-21 23:33:04 +03:00
|
|
|
open Utils
|
2022-08-12 18:59:49 +03:00
|
|
|
open Shared_ast
|
2020-11-23 18:12:45 +03:00
|
|
|
|
2022-01-31 20:09:14 +03:00
|
|
|
type scope_var_ctx = {
|
2022-08-17 18:14:29 +03:00
|
|
|
scope_var_name : ScopeVar.t;
|
2022-08-25 18:29:00 +03:00
|
|
|
scope_var_typ : naked_typ;
|
2022-02-07 12:30:36 +03:00
|
|
|
scope_var_io : Ast.io;
|
2022-01-31 20:09:14 +03:00
|
|
|
}
|
|
|
|
|
2022-09-30 17:52:35 +03:00
|
|
|
type 'm scope_sig_ctx = {
|
2022-01-31 20:09:14 +03:00
|
|
|
scope_sig_local_vars : scope_var_ctx list; (** List of scope variables *)
|
2022-09-30 17:52:35 +03:00
|
|
|
scope_sig_scope_var : 'm Dcalc.Ast.expr Var.t;
|
2022-07-11 12:34:01 +03:00
|
|
|
(** Var representing the scope *)
|
2022-09-30 17:52:35 +03:00
|
|
|
scope_sig_input_var : 'm Dcalc.Ast.expr Var.t;
|
2022-01-31 20:09:14 +03:00
|
|
|
(** Var representing the scope input inside the scope func *)
|
2022-08-12 23:42:39 +03:00
|
|
|
scope_sig_input_struct : StructName.t; (** Scope input *)
|
|
|
|
scope_sig_output_struct : StructName.t; (** Scope output *)
|
2022-01-31 20:09:14 +03:00
|
|
|
}
|
|
|
|
|
2022-09-30 17:52:35 +03:00
|
|
|
type 'm scope_sigs_ctx = 'm scope_sig_ctx ScopeMap.t
|
2020-11-26 19:06:32 +03:00
|
|
|
|
2022-09-23 18:43:48 +03:00
|
|
|
type 'm ctx = {
|
2022-08-25 13:09:51 +03:00
|
|
|
structs : struct_ctx;
|
|
|
|
enums : enum_ctx;
|
2022-08-12 23:42:39 +03:00
|
|
|
scope_name : ScopeName.t;
|
2022-09-30 17:52:35 +03:00
|
|
|
scopes_parameters : 'm scope_sigs_ctx;
|
|
|
|
scope_vars : ('m Dcalc.Ast.expr Var.t * naked_typ * Ast.io) ScopeVarMap.t;
|
2022-03-08 17:03:14 +03:00
|
|
|
subscope_vars :
|
2022-09-30 17:52:35 +03:00
|
|
|
('m Dcalc.Ast.expr Var.t * naked_typ * Ast.io) ScopeVarMap.t SubScopeMap.t;
|
|
|
|
local_vars : ('m Ast.expr, 'm Dcalc.Ast.expr Var.t) Var.Map.t;
|
2020-11-23 20:51:06 +03:00
|
|
|
}
|
|
|
|
|
2022-03-08 17:03:14 +03:00
|
|
|
let empty_ctx
|
2022-08-25 13:09:51 +03:00
|
|
|
(struct_ctx : struct_ctx)
|
|
|
|
(enum_ctx : enum_ctx)
|
2022-09-30 17:52:35 +03:00
|
|
|
(scopes_ctx : 'm scope_sigs_ctx)
|
2022-08-12 23:42:39 +03:00
|
|
|
(scope_name : ScopeName.t) =
|
2020-11-23 20:51:06 +03:00
|
|
|
{
|
2020-12-04 16:41:20 +03:00
|
|
|
structs = struct_ctx;
|
|
|
|
enums = enum_ctx;
|
2020-12-10 18:58:32 +03:00
|
|
|
scope_name;
|
2020-11-26 19:06:32 +03:00
|
|
|
scopes_parameters = scopes_ctx;
|
2022-08-25 17:08:08 +03:00
|
|
|
scope_vars = ScopeVarMap.empty;
|
2022-09-14 16:36:24 +03:00
|
|
|
subscope_vars = SubScopeMap.empty;
|
2022-08-25 13:09:51 +03:00
|
|
|
local_vars = Var.Map.empty;
|
2020-11-23 20:51:06 +03:00
|
|
|
}
|
2020-11-23 18:12:45 +03:00
|
|
|
|
2022-09-30 19:30:06 +03:00
|
|
|
let mark_tany m pos =
|
|
|
|
Expr.with_ty m (Marked.mark pos TAny) ~pos
|
|
|
|
|
|
|
|
(* Expression argument is used as a type witness, its type and positions aren't
|
|
|
|
used *)
|
|
|
|
let pos_mark_mk (type a m) (e : (a, m mark) gexpr):
|
|
|
|
(Pos.t -> m mark) *
|
|
|
|
((_, Pos.t) Marked.t -> m mark) =
|
|
|
|
let pos_mark pos =
|
|
|
|
Expr.map_mark (fun _ -> pos) (fun _ -> TAny, pos) (Marked.get_mark e)
|
|
|
|
in
|
|
|
|
let pos_mark_as e =
|
|
|
|
pos_mark (Marked.get_mark e)
|
|
|
|
in
|
|
|
|
pos_mark, pos_mark_as
|
2022-05-31 19:38:14 +03:00
|
|
|
|
2022-03-08 17:03:14 +03:00
|
|
|
let merge_defaults
|
2022-09-12 18:03:44 +03:00
|
|
|
(caller : 'a Dcalc.Ast.expr Bindlib.box)
|
|
|
|
(callee : 'a Dcalc.Ast.expr Bindlib.box) : 'a Dcalc.Ast.expr Bindlib.box =
|
2020-11-26 17:48:26 +03:00
|
|
|
let caller =
|
2022-07-11 12:32:23 +03:00
|
|
|
let m = Marked.get_mark (Bindlib.unbox caller) in
|
2022-09-12 18:03:44 +03:00
|
|
|
let pos = Expr.mark_pos m in
|
|
|
|
Expr.make_app caller
|
2022-09-12 18:23:44 +03:00
|
|
|
[Bindlib.box (ELit LUnit, Expr.with_ty m (Marked.mark pos (TLit TUnit)))]
|
2022-09-12 18:03:44 +03:00
|
|
|
pos
|
2020-11-26 17:48:26 +03:00
|
|
|
in
|
|
|
|
let body =
|
|
|
|
Bindlib.box_apply2
|
|
|
|
(fun caller callee ->
|
2022-07-11 12:34:01 +03:00
|
|
|
let m = Marked.get_mark callee in
|
2022-09-30 19:30:06 +03:00
|
|
|
let ltrue =
|
|
|
|
Marked.mark (Expr.with_ty m (Marked.mark (Expr.mark_pos m) (TLit TBool)))
|
|
|
|
(ELit (LBool true))
|
|
|
|
in
|
|
|
|
Marked.mark m (EDefault ([caller], ltrue, callee)))
|
2020-11-26 17:48:26 +03:00
|
|
|
caller callee
|
|
|
|
in
|
2020-11-27 13:54:22 +03:00
|
|
|
body
|
2020-11-23 18:12:45 +03:00
|
|
|
|
2022-03-08 17:03:14 +03:00
|
|
|
let tag_with_log_entry
|
2022-09-30 19:30:06 +03:00
|
|
|
(e : 'm Dcalc.Ast.expr Bindlib.box)
|
2022-08-12 23:42:39 +03:00
|
|
|
(l : log_entry)
|
2022-03-08 17:03:14 +03:00
|
|
|
(markings : Utils.Uid.MarkedString.info list) :
|
2022-09-30 19:30:06 +03:00
|
|
|
'm Dcalc.Ast.expr Bindlib.box =
|
2021-01-21 23:33:04 +03:00
|
|
|
Bindlib.box_apply
|
|
|
|
(fun e ->
|
2022-09-30 19:30:06 +03:00
|
|
|
let m = mark_tany (Marked.get_mark e) (Expr.pos e) in
|
|
|
|
Marked.mark m
|
|
|
|
(EApp (Marked.mark m (EOp (Unop (Log (l, markings)))), [e])))
|
2021-01-21 23:33:04 +03:00
|
|
|
e
|
|
|
|
|
2022-05-25 15:54:59 +03:00
|
|
|
(* In a list of exceptions, it is normally an error if more than a single one
|
|
|
|
apply at the same time. This relaxes this constraint slightly, allowing a
|
|
|
|
conflict if all the triggered conflicting exception yield syntactically equal
|
|
|
|
results (and as long as none of these exceptions have exceptions themselves)
|
|
|
|
|
|
|
|
NOTE: the choice of the exception that will be triggered and show in the
|
|
|
|
trace is arbitrary (but deterministic). *)
|
2022-09-26 17:05:57 +03:00
|
|
|
let collapse_similar_outcomes (type m) (excepts : m Ast.expr list) :
|
|
|
|
m Ast.expr list =
|
2022-09-23 18:43:48 +03:00
|
|
|
let module ExprMap = Map.Make (struct
|
2022-09-26 17:05:57 +03:00
|
|
|
type t = m Ast.expr
|
|
|
|
|
|
|
|
let compare = Expr.compare
|
|
|
|
end) in
|
2022-05-25 15:54:59 +03:00
|
|
|
let cons_map =
|
|
|
|
List.fold_left
|
|
|
|
(fun map -> function
|
2022-08-25 13:09:51 +03:00
|
|
|
| (EDefault ([], _, cons), _) as e ->
|
2022-09-23 18:43:48 +03:00
|
|
|
ExprMap.update cons
|
2022-05-25 15:54:59 +03:00
|
|
|
(fun prev -> Some (e :: Option.value ~default:[] prev))
|
|
|
|
map
|
|
|
|
| _ -> map)
|
2022-09-23 18:43:48 +03:00
|
|
|
ExprMap.empty excepts
|
2022-05-25 15:54:59 +03:00
|
|
|
in
|
|
|
|
let _, excepts =
|
|
|
|
List.fold_right
|
|
|
|
(fun e (cons_map, excepts) ->
|
|
|
|
match e with
|
2022-08-25 13:09:51 +03:00
|
|
|
| EDefault ([], _, cons), _ ->
|
2022-05-25 15:54:59 +03:00
|
|
|
let collapsed_exc =
|
|
|
|
List.fold_left
|
|
|
|
(fun acc -> function
|
2022-08-25 13:09:51 +03:00
|
|
|
| EDefault ([], just, cons), pos ->
|
|
|
|
[EDefault (acc, just, cons), pos]
|
2022-05-25 15:54:59 +03:00
|
|
|
| _ -> assert false)
|
|
|
|
[]
|
2022-09-23 18:43:48 +03:00
|
|
|
(ExprMap.find cons cons_map)
|
2022-05-25 15:54:59 +03:00
|
|
|
in
|
2022-09-23 18:43:48 +03:00
|
|
|
ExprMap.add cons [] cons_map, collapsed_exc @ excepts
|
2022-05-25 15:54:59 +03:00
|
|
|
| e -> cons_map, e :: excepts)
|
|
|
|
excepts (cons_map, [])
|
|
|
|
in
|
|
|
|
excepts
|
|
|
|
|
2022-09-23 18:43:48 +03:00
|
|
|
let rec translate_expr (ctx : 'm ctx) (e : 'm Ast.expr) :
|
|
|
|
'm Dcalc.Ast.expr Bindlib.box =
|
2022-08-26 16:21:47 +03:00
|
|
|
Bindlib.box_apply (fun x -> Marked.same_mark_as x e)
|
2022-07-11 12:34:01 +03:00
|
|
|
@@
|
|
|
|
match Marked.unmark e with
|
2022-08-25 13:09:51 +03:00
|
|
|
| EVar v -> Bindlib.box_var (Var.Map.find v ctx.local_vars)
|
|
|
|
| ELit
|
|
|
|
(( LBool _ | LEmptyError | LInt _ | LRat _ | LMoney _ | LUnit | LDate _
|
|
|
|
| LDuration _ ) as l) ->
|
|
|
|
Bindlib.box (ELit l)
|
2022-07-11 12:34:01 +03:00
|
|
|
| EStruct (struct_name, e_fields) ->
|
2022-08-12 23:42:39 +03:00
|
|
|
let struct_sig = StructMap.find struct_name ctx.structs in
|
2022-07-11 12:34:01 +03:00
|
|
|
let d_fields, remaining_e_fields =
|
|
|
|
List.fold_right
|
|
|
|
(fun (field_name, _) (d_fields, e_fields) ->
|
2022-08-17 18:14:29 +03:00
|
|
|
let field_e = StructFieldMap.find field_name e_fields in
|
2022-07-11 12:34:01 +03:00
|
|
|
let field_d = translate_expr ctx field_e in
|
2022-08-17 18:14:29 +03:00
|
|
|
field_d :: d_fields, StructFieldMap.remove field_name e_fields)
|
2022-07-11 12:34:01 +03:00
|
|
|
struct_sig ([], e_fields)
|
|
|
|
in
|
2022-08-17 18:14:29 +03:00
|
|
|
if StructFieldMap.cardinal remaining_e_fields > 0 then
|
2022-08-26 16:21:47 +03:00
|
|
|
Errors.raise_spanned_error (Expr.pos e)
|
2022-07-11 12:34:01 +03:00
|
|
|
"The fields \"%a\" do not belong to the structure %a"
|
2022-08-12 23:42:39 +03:00
|
|
|
StructName.format_t struct_name
|
2022-07-11 12:34:01 +03:00
|
|
|
(Format.pp_print_list
|
|
|
|
~pp_sep:(fun fmt () -> Format.fprintf fmt ", ")
|
|
|
|
(fun fmt (field_name, _) ->
|
2022-08-12 23:42:39 +03:00
|
|
|
Format.fprintf fmt "%a" StructFieldName.format_t field_name))
|
2022-08-17 18:14:29 +03:00
|
|
|
(StructFieldMap.bindings remaining_e_fields)
|
2022-07-11 12:34:01 +03:00
|
|
|
else
|
2022-05-04 18:40:55 +03:00
|
|
|
Bindlib.box_apply
|
2022-08-12 23:42:39 +03:00
|
|
|
(fun d_fields -> ETuple (d_fields, Some struct_name))
|
2022-07-11 12:34:01 +03:00
|
|
|
(Bindlib.box_list d_fields)
|
|
|
|
| EStructAccess (e1, field_name, struct_name) ->
|
2022-08-12 23:42:39 +03:00
|
|
|
let struct_sig = StructMap.find struct_name ctx.structs in
|
2022-07-11 12:34:01 +03:00
|
|
|
let _, field_index =
|
|
|
|
try
|
|
|
|
List.assoc field_name (List.mapi (fun i (x, y) -> x, (y, i)) struct_sig)
|
|
|
|
with Not_found ->
|
2022-08-26 16:21:47 +03:00
|
|
|
Errors.raise_spanned_error (Expr.pos e)
|
2022-07-11 12:34:01 +03:00
|
|
|
"The field \"%a\" does not belong to the structure %a"
|
2022-08-16 11:04:01 +03:00
|
|
|
StructFieldName.format_t field_name StructName.format_t struct_name
|
2022-07-11 12:34:01 +03:00
|
|
|
in
|
|
|
|
let e1 = translate_expr ctx e1 in
|
|
|
|
Bindlib.box_apply
|
|
|
|
(fun e1 ->
|
2022-08-25 13:09:51 +03:00
|
|
|
ETupleAccess (e1, field_index, Some struct_name, List.map snd struct_sig))
|
2022-07-11 12:34:01 +03:00
|
|
|
e1
|
|
|
|
| EEnumInj (e1, constructor, enum_name) ->
|
2022-08-12 23:42:39 +03:00
|
|
|
let enum_sig = EnumMap.find enum_name ctx.enums in
|
2022-07-11 12:34:01 +03:00
|
|
|
let _, constructor_index =
|
|
|
|
try
|
|
|
|
List.assoc constructor (List.mapi (fun i (x, y) -> x, (y, i)) enum_sig)
|
|
|
|
with Not_found ->
|
2022-08-26 16:21:47 +03:00
|
|
|
Errors.raise_spanned_error (Expr.pos e)
|
2022-07-11 12:34:01 +03:00
|
|
|
"The constructor \"%a\" does not belong to the enum %a"
|
2022-08-16 11:04:01 +03:00
|
|
|
EnumConstructor.format_t constructor EnumName.format_t enum_name
|
2022-07-11 12:34:01 +03:00
|
|
|
in
|
|
|
|
let e1 = translate_expr ctx e1 in
|
|
|
|
Bindlib.box_apply
|
2022-08-25 13:09:51 +03:00
|
|
|
(fun e1 -> EInj (e1, constructor_index, enum_name, List.map snd enum_sig))
|
2022-07-11 12:34:01 +03:00
|
|
|
e1
|
2022-08-25 13:09:51 +03:00
|
|
|
| EMatchS (e1, enum_name, cases) ->
|
2022-08-12 23:42:39 +03:00
|
|
|
let enum_sig = EnumMap.find enum_name ctx.enums in
|
2022-07-11 12:34:01 +03:00
|
|
|
let d_cases, remaining_e_cases =
|
|
|
|
List.fold_right
|
|
|
|
(fun (constructor, _) (d_cases, e_cases) ->
|
|
|
|
let case_e =
|
2022-08-17 18:14:29 +03:00
|
|
|
try EnumConstructorMap.find constructor e_cases
|
2022-07-11 12:34:01 +03:00
|
|
|
with Not_found ->
|
2022-08-26 16:21:47 +03:00
|
|
|
Errors.raise_spanned_error (Expr.pos e)
|
2022-07-11 12:34:01 +03:00
|
|
|
"The constructor %a of enum %a is missing from this pattern \
|
|
|
|
matching"
|
2022-08-16 11:04:01 +03:00
|
|
|
EnumConstructor.format_t constructor EnumName.format_t enum_name
|
2022-07-11 12:34:01 +03:00
|
|
|
in
|
|
|
|
let case_d = translate_expr ctx case_e in
|
2022-08-17 18:14:29 +03:00
|
|
|
case_d :: d_cases, EnumConstructorMap.remove constructor e_cases)
|
2022-07-11 12:34:01 +03:00
|
|
|
enum_sig ([], cases)
|
|
|
|
in
|
2022-08-17 18:14:29 +03:00
|
|
|
if EnumConstructorMap.cardinal remaining_e_cases > 0 then
|
2022-08-26 16:21:47 +03:00
|
|
|
Errors.raise_spanned_error (Expr.pos e)
|
2022-09-26 19:19:39 +03:00
|
|
|
"Pattern matching is incomplete for enum %a: missing cases %a"
|
2022-08-12 23:42:39 +03:00
|
|
|
EnumName.format_t enum_name
|
2022-07-11 12:34:01 +03:00
|
|
|
(Format.pp_print_list
|
|
|
|
~pp_sep:(fun fmt () -> Format.fprintf fmt ", ")
|
|
|
|
(fun fmt (case_name, _) ->
|
2022-08-12 23:42:39 +03:00
|
|
|
Format.fprintf fmt "%a" EnumConstructor.format_t case_name))
|
2022-08-17 18:14:29 +03:00
|
|
|
(EnumConstructorMap.bindings remaining_e_cases)
|
2022-07-11 12:34:01 +03:00
|
|
|
else
|
|
|
|
let e1 = translate_expr ctx e1 in
|
|
|
|
Bindlib.box_apply2
|
2022-08-12 23:42:39 +03:00
|
|
|
(fun d_fields e1 -> EMatch (e1, d_fields, enum_name))
|
2022-07-11 12:34:01 +03:00
|
|
|
(Bindlib.box_list d_cases) e1
|
|
|
|
| EApp (e1, args) ->
|
|
|
|
(* We insert various log calls to record arguments and outputs of
|
|
|
|
user-defined functions belonging to scopes *)
|
|
|
|
let e1_func = translate_expr ctx e1 in
|
|
|
|
let markings l =
|
|
|
|
match l with
|
2022-08-25 13:09:51 +03:00
|
|
|
| ScopelangScopeVar (v, _) ->
|
2022-08-17 18:14:29 +03:00
|
|
|
[ScopeName.get_info ctx.scope_name; ScopeVar.get_info v]
|
2022-08-25 13:09:51 +03:00
|
|
|
| SubScopeVar (s, _, (v, _)) ->
|
2022-08-17 18:14:29 +03:00
|
|
|
[ScopeName.get_info s; ScopeVar.get_info v]
|
2022-07-11 12:34:01 +03:00
|
|
|
in
|
|
|
|
let e1_func =
|
|
|
|
match Marked.unmark e1 with
|
2022-08-16 11:04:01 +03:00
|
|
|
| ELocation l -> tag_with_log_entry e1_func BeginCall (markings l)
|
2022-07-11 12:34:01 +03:00
|
|
|
| _ -> e1_func
|
|
|
|
in
|
|
|
|
let new_args = List.map (translate_expr ctx) args in
|
|
|
|
let input_typ, output_typ =
|
|
|
|
(* NOTE: this is a temporary solution, it works because it's assume that
|
|
|
|
all function calls are from scope variable. However, this will change
|
|
|
|
-- for more information see
|
|
|
|
https://github.com/CatalaLang/catala/pull/280#discussion_r898851693. *)
|
|
|
|
let retrieve_in_and_out_typ_or_any var vars =
|
2022-08-25 17:08:08 +03:00
|
|
|
let _, typ, _ = ScopeVarMap.find (Marked.unmark var) vars in
|
2022-07-11 12:34:01 +03:00
|
|
|
match typ with
|
2022-08-12 23:42:39 +03:00
|
|
|
| TArrow (marked_input_typ, marked_output_typ) ->
|
2022-07-11 12:34:01 +03:00
|
|
|
Marked.unmark marked_input_typ, Marked.unmark marked_output_typ
|
2022-08-12 23:42:39 +03:00
|
|
|
| _ -> TAny, TAny
|
2022-06-15 15:34:15 +03:00
|
|
|
in
|
2022-07-11 12:34:01 +03:00
|
|
|
match Marked.unmark e1 with
|
2022-08-25 13:09:51 +03:00
|
|
|
| ELocation (ScopelangScopeVar var) ->
|
2022-07-11 12:34:01 +03:00
|
|
|
retrieve_in_and_out_typ_or_any var ctx.scope_vars
|
|
|
|
| ELocation (SubScopeVar (_, sname, var)) ->
|
|
|
|
ctx.subscope_vars
|
2022-09-14 16:36:24 +03:00
|
|
|
|> SubScopeMap.find (Marked.unmark sname)
|
2022-07-11 12:34:01 +03:00
|
|
|
|> retrieve_in_and_out_typ_or_any var
|
2022-08-12 23:42:39 +03:00
|
|
|
| _ -> TAny, TAny
|
2022-07-11 12:34:01 +03:00
|
|
|
in
|
|
|
|
let new_args =
|
|
|
|
match Marked.unmark e1, new_args with
|
|
|
|
| ELocation l, [new_arg] ->
|
|
|
|
[
|
2022-08-12 23:42:39 +03:00
|
|
|
tag_with_log_entry new_arg (VarDef input_typ)
|
2022-08-26 16:21:47 +03:00
|
|
|
(markings l @ [Marked.mark (Expr.pos e) "input"]);
|
2022-07-11 12:34:01 +03:00
|
|
|
]
|
|
|
|
| _ -> new_args
|
|
|
|
in
|
|
|
|
let new_e =
|
|
|
|
Bindlib.box_apply2
|
2022-08-26 16:21:47 +03:00
|
|
|
(fun e' u -> Marked.same_mark_as (EApp (e', u)) e)
|
2022-07-11 12:34:01 +03:00
|
|
|
e1_func
|
|
|
|
(Bindlib.box_list new_args)
|
|
|
|
in
|
|
|
|
let new_e =
|
|
|
|
match Marked.unmark e1 with
|
|
|
|
| ELocation l ->
|
|
|
|
tag_with_log_entry
|
2022-08-12 23:42:39 +03:00
|
|
|
(tag_with_log_entry new_e (VarDef output_typ)
|
2022-08-26 16:21:47 +03:00
|
|
|
(markings l @ [Marked.mark (Expr.pos e) "output"]))
|
2022-08-12 23:42:39 +03:00
|
|
|
EndCall (markings l)
|
2022-07-11 12:34:01 +03:00
|
|
|
| _ -> new_e
|
|
|
|
in
|
|
|
|
Bindlib.box_apply Marked.unmark new_e
|
|
|
|
| EAbs (binder, typ) ->
|
|
|
|
let xs, body = Bindlib.unmbind binder in
|
2022-07-28 11:36:36 +03:00
|
|
|
let new_xs = Array.map (fun x -> Var.make (Bindlib.name_of x)) xs in
|
2022-07-11 12:34:01 +03:00
|
|
|
let both_xs = Array.map2 (fun x new_x -> x, new_x) xs new_xs in
|
|
|
|
let body =
|
|
|
|
translate_expr
|
|
|
|
{
|
|
|
|
ctx with
|
|
|
|
local_vars =
|
|
|
|
Array.fold_left
|
2022-08-25 13:09:51 +03:00
|
|
|
(fun local_vars (x, new_x) -> Var.Map.add x new_x local_vars)
|
2022-07-11 12:34:01 +03:00
|
|
|
ctx.local_vars both_xs;
|
|
|
|
}
|
|
|
|
body
|
|
|
|
in
|
|
|
|
let binder = Bindlib.bind_mvar new_xs body in
|
2022-08-25 13:09:51 +03:00
|
|
|
Bindlib.box_apply (fun b -> EAbs (b, typ)) binder
|
2022-07-11 12:34:01 +03:00
|
|
|
| EDefault (excepts, just, cons) ->
|
|
|
|
let excepts = collapse_similar_outcomes excepts in
|
|
|
|
Bindlib.box_apply3
|
2022-08-12 23:42:39 +03:00
|
|
|
(fun e j c -> EDefault (e, j, c))
|
2022-07-11 12:34:01 +03:00
|
|
|
(Bindlib.box_list (List.map (translate_expr ctx) excepts))
|
|
|
|
(translate_expr ctx just) (translate_expr ctx cons)
|
2022-08-25 13:09:51 +03:00
|
|
|
| ELocation (ScopelangScopeVar a) ->
|
2022-08-25 17:08:08 +03:00
|
|
|
let v, _, _ = ScopeVarMap.find (Marked.unmark a) ctx.scope_vars in
|
2022-07-11 12:34:01 +03:00
|
|
|
Bindlib.box_var v
|
|
|
|
| ELocation (SubScopeVar (_, s, a)) -> (
|
|
|
|
try
|
|
|
|
let v, _, _ =
|
2022-08-25 17:08:08 +03:00
|
|
|
ScopeVarMap.find (Marked.unmark a)
|
2022-09-14 16:36:24 +03:00
|
|
|
(SubScopeMap.find (Marked.unmark s) ctx.subscope_vars)
|
2022-05-04 18:40:55 +03:00
|
|
|
in
|
|
|
|
Bindlib.box_var v
|
2022-07-11 12:34:01 +03:00
|
|
|
with Not_found ->
|
|
|
|
Errors.raise_multispanned_error
|
|
|
|
[
|
2022-08-26 16:21:47 +03:00
|
|
|
Some "Incriminated variable usage:", Expr.pos e;
|
2022-07-11 12:34:01 +03:00
|
|
|
( Some "Incriminated subscope variable declaration:",
|
2022-08-17 18:14:29 +03:00
|
|
|
Marked.get_mark (ScopeVar.get_info (Marked.unmark a)) );
|
2022-07-11 12:34:01 +03:00
|
|
|
( Some "Incriminated subscope declaration:",
|
2022-08-17 18:14:29 +03:00
|
|
|
Marked.get_mark (SubScopeName.get_info (Marked.unmark s)) );
|
2022-07-11 12:34:01 +03:00
|
|
|
]
|
|
|
|
"The variable %a.%a cannot be used here, as it is not part subscope \
|
|
|
|
%a's results. Maybe you forgot to qualify it as an output?"
|
2022-08-17 18:14:29 +03:00
|
|
|
SubScopeName.format_t (Marked.unmark s) ScopeVar.format_t
|
|
|
|
(Marked.unmark a) SubScopeName.format_t (Marked.unmark s))
|
2022-07-11 12:34:01 +03:00
|
|
|
| EIfThenElse (cond, et, ef) ->
|
|
|
|
Bindlib.box_apply3
|
2022-08-12 23:42:39 +03:00
|
|
|
(fun c t f -> EIfThenElse (c, t, f))
|
2022-07-11 12:34:01 +03:00
|
|
|
(translate_expr ctx cond) (translate_expr ctx et) (translate_expr ctx ef)
|
2022-08-12 23:42:39 +03:00
|
|
|
| EOp op -> Bindlib.box (EOp op)
|
2022-07-11 12:34:01 +03:00
|
|
|
| ErrorOnEmpty e' ->
|
2022-08-16 11:04:01 +03:00
|
|
|
Bindlib.box_apply (fun e' -> ErrorOnEmpty e') (translate_expr ctx e')
|
2022-07-11 12:34:01 +03:00
|
|
|
| EArray es ->
|
|
|
|
Bindlib.box_apply
|
2022-08-12 23:42:39 +03:00
|
|
|
(fun es -> EArray es)
|
2022-07-11 12:34:01 +03:00
|
|
|
(Bindlib.box_list (List.map (translate_expr ctx) es))
|
2020-11-23 18:12:45 +03:00
|
|
|
|
2022-03-08 17:03:14 +03:00
|
|
|
(** The result of a rule translation is a list of assignment, with variables and
|
|
|
|
expressions. We also return the new translation context available after the
|
2022-04-02 15:51:11 +03:00
|
|
|
assignment to use in later rule translations. The list is actually a
|
|
|
|
continuation yielding a [Dcalc.scope_body_expr] by giving it what should
|
|
|
|
come later in the chain of let-bindings. *)
|
2022-03-08 17:03:14 +03:00
|
|
|
let translate_rule
|
2022-09-23 18:43:48 +03:00
|
|
|
(ctx : 'm ctx)
|
|
|
|
(rule : 'm Ast.rule)
|
2022-03-08 17:03:14 +03:00
|
|
|
((sigma_name, pos_sigma) : Utils.Uid.MarkedString.info) :
|
2022-09-23 18:43:48 +03:00
|
|
|
('m Dcalc.Ast.expr scope_body_expr Bindlib.box ->
|
|
|
|
'm Dcalc.Ast.expr scope_body_expr Bindlib.box)
|
|
|
|
* 'm ctx =
|
2020-11-23 20:51:06 +03:00
|
|
|
match rule with
|
2022-08-25 13:09:51 +03:00
|
|
|
| Definition ((ScopelangScopeVar a, var_def_pos), tau, a_io, e) ->
|
2022-09-30 19:30:06 +03:00
|
|
|
let pos_mark, pos_mark_as = pos_mark_mk e in
|
2022-08-17 18:14:29 +03:00
|
|
|
let a_name = ScopeVar.get_info (Marked.unmark a) in
|
2022-07-28 11:36:36 +03:00
|
|
|
let a_var = Var.make (Marked.unmark a_name) in
|
2022-05-04 18:40:55 +03:00
|
|
|
let new_e = translate_expr ctx e in
|
2022-08-17 12:49:16 +03:00
|
|
|
let a_expr = Expr.make_var (a_var, pos_mark var_def_pos) in
|
2022-05-04 18:40:55 +03:00
|
|
|
let merged_expr =
|
|
|
|
Bindlib.box_apply
|
2022-08-16 11:04:01 +03:00
|
|
|
(fun merged_expr -> ErrorOnEmpty merged_expr, pos_mark_as a_name)
|
2022-05-30 12:20:48 +03:00
|
|
|
(match Marked.unmark a_io.io_input with
|
2022-05-04 18:40:55 +03:00
|
|
|
| OnlyInput ->
|
|
|
|
failwith "should not happen"
|
|
|
|
(* scopelang should not contain any definitions of input only
|
|
|
|
variables *)
|
|
|
|
| Reentrant -> merge_defaults a_expr new_e
|
|
|
|
| NoInput -> new_e)
|
|
|
|
in
|
|
|
|
let merged_expr =
|
|
|
|
tag_with_log_entry merged_expr
|
2022-08-12 23:42:39 +03:00
|
|
|
(VarDef (Marked.unmark tau))
|
2022-05-04 16:48:03 +03:00
|
|
|
[sigma_name, pos_sigma; a_name]
|
2022-05-04 18:40:55 +03:00
|
|
|
in
|
|
|
|
( (fun next ->
|
|
|
|
Bindlib.box_apply2
|
|
|
|
(fun next merged_expr ->
|
2022-08-12 23:42:39 +03:00
|
|
|
ScopeLet
|
2022-05-04 18:40:55 +03:00
|
|
|
{
|
2022-08-12 23:42:39 +03:00
|
|
|
scope_let_next = next;
|
|
|
|
scope_let_typ = tau;
|
|
|
|
scope_let_expr = merged_expr;
|
|
|
|
scope_let_kind = ScopeVarDefinition;
|
|
|
|
scope_let_pos = Marked.get_mark a;
|
2022-05-04 18:40:55 +03:00
|
|
|
})
|
|
|
|
(Bindlib.bind_var a_var next)
|
|
|
|
merged_expr),
|
|
|
|
{
|
|
|
|
ctx with
|
|
|
|
scope_vars =
|
2022-08-25 17:08:08 +03:00
|
|
|
ScopeVarMap.add (Marked.unmark a)
|
2022-05-30 12:20:48 +03:00
|
|
|
(a_var, Marked.unmark tau, a_io)
|
2022-05-04 18:40:55 +03:00
|
|
|
ctx.scope_vars;
|
|
|
|
} )
|
2022-03-08 17:03:14 +03:00
|
|
|
| Definition
|
|
|
|
( (SubScopeVar (_subs_name, subs_index, subs_var), var_def_pos),
|
|
|
|
tau,
|
|
|
|
a_io,
|
|
|
|
e ) ->
|
2022-09-30 19:30:06 +03:00
|
|
|
let _pos_mark, pos_mark_as = pos_mark_mk e in
|
2022-05-04 18:40:55 +03:00
|
|
|
let a_name =
|
2022-05-30 12:20:48 +03:00
|
|
|
Marked.map_under_mark
|
2022-05-04 18:40:55 +03:00
|
|
|
(fun str ->
|
2022-08-17 18:14:29 +03:00
|
|
|
str ^ "." ^ Marked.unmark (ScopeVar.get_info (Marked.unmark subs_var)))
|
|
|
|
(SubScopeName.get_info (Marked.unmark subs_index))
|
2022-05-04 18:40:55 +03:00
|
|
|
in
|
2022-07-28 11:36:36 +03:00
|
|
|
let a_var = Var.make (Marked.unmark a_name) in
|
2022-05-04 18:40:55 +03:00
|
|
|
let new_e =
|
|
|
|
tag_with_log_entry (translate_expr ctx e)
|
2022-08-12 23:42:39 +03:00
|
|
|
(VarDef (Marked.unmark tau))
|
2022-05-04 16:48:03 +03:00
|
|
|
[sigma_name, pos_sigma; a_name]
|
2022-05-04 18:40:55 +03:00
|
|
|
in
|
2022-07-28 11:36:36 +03:00
|
|
|
let silent_var = Var.make "_" in
|
2022-05-04 18:40:55 +03:00
|
|
|
let thunked_or_nonempty_new_e =
|
2022-05-30 12:20:48 +03:00
|
|
|
match Marked.unmark a_io.io_input with
|
2022-05-04 18:40:55 +03:00
|
|
|
| NoInput -> failwith "should not happen"
|
|
|
|
| OnlyInput ->
|
2021-02-01 17:57:19 +03:00
|
|
|
Bindlib.box_apply
|
2022-08-12 23:42:39 +03:00
|
|
|
(fun new_e -> ErrorOnEmpty new_e, pos_mark_as subs_var)
|
2022-05-04 18:40:55 +03:00
|
|
|
new_e
|
|
|
|
| Reentrant ->
|
2022-08-22 19:53:30 +03:00
|
|
|
Expr.make_abs [| silent_var |] new_e
|
2022-08-12 23:42:39 +03:00
|
|
|
[TLit TUnit, var_def_pos]
|
2022-09-12 18:03:44 +03:00
|
|
|
var_def_pos
|
2022-05-04 18:40:55 +03:00
|
|
|
in
|
|
|
|
( (fun next ->
|
2022-04-02 15:51:11 +03:00
|
|
|
Bindlib.box_apply2
|
2022-05-04 18:40:55 +03:00
|
|
|
(fun next thunked_or_nonempty_new_e ->
|
2022-08-12 23:42:39 +03:00
|
|
|
ScopeLet
|
2022-04-02 15:51:11 +03:00
|
|
|
{
|
2022-08-12 23:42:39 +03:00
|
|
|
scope_let_next = next;
|
|
|
|
scope_let_pos = Marked.get_mark a_name;
|
|
|
|
scope_let_typ =
|
2022-05-30 12:20:48 +03:00
|
|
|
(match Marked.unmark a_io.io_input with
|
2022-05-04 18:40:55 +03:00
|
|
|
| NoInput -> failwith "should not happen"
|
|
|
|
| OnlyInput -> tau
|
|
|
|
| Reentrant ->
|
2022-08-16 11:04:01 +03:00
|
|
|
TArrow ((TLit TUnit, var_def_pos), tau), var_def_pos);
|
2022-08-12 23:42:39 +03:00
|
|
|
scope_let_expr = thunked_or_nonempty_new_e;
|
|
|
|
scope_let_kind = SubScopeVarDefinition;
|
2022-04-02 15:51:11 +03:00
|
|
|
})
|
2022-05-04 18:40:55 +03:00
|
|
|
(Bindlib.bind_var a_var next)
|
|
|
|
thunked_or_nonempty_new_e),
|
|
|
|
{
|
|
|
|
ctx with
|
|
|
|
subscope_vars =
|
2022-09-14 16:36:24 +03:00
|
|
|
SubScopeMap.update (Marked.unmark subs_index)
|
2022-05-04 18:40:55 +03:00
|
|
|
(fun map ->
|
|
|
|
match map with
|
|
|
|
| Some map ->
|
|
|
|
Some
|
2022-08-25 17:08:08 +03:00
|
|
|
(ScopeVarMap.add (Marked.unmark subs_var)
|
2022-05-30 12:20:48 +03:00
|
|
|
(a_var, Marked.unmark tau, a_io)
|
2022-05-04 18:40:55 +03:00
|
|
|
map)
|
|
|
|
| None ->
|
|
|
|
Some
|
2022-08-25 17:08:08 +03:00
|
|
|
(ScopeVarMap.singleton (Marked.unmark subs_var)
|
2022-05-30 12:20:48 +03:00
|
|
|
(a_var, Marked.unmark tau, a_io)))
|
2022-05-04 18:40:55 +03:00
|
|
|
ctx.subscope_vars;
|
|
|
|
} )
|
2022-09-30 17:52:35 +03:00
|
|
|
| Call (subname, subindex, m) ->
|
2022-09-14 16:36:24 +03:00
|
|
|
let subscope_sig = ScopeMap.find subname ctx.scopes_parameters in
|
2022-05-04 18:40:55 +03:00
|
|
|
let all_subscope_vars = subscope_sig.scope_sig_local_vars in
|
|
|
|
let all_subscope_input_vars =
|
|
|
|
List.filter
|
|
|
|
(fun var_ctx ->
|
2022-05-30 12:20:48 +03:00
|
|
|
match Marked.unmark var_ctx.scope_var_io.Ast.io_input with
|
2022-05-04 18:40:55 +03:00
|
|
|
| NoInput -> false
|
|
|
|
| _ -> true)
|
|
|
|
all_subscope_vars
|
|
|
|
in
|
|
|
|
let all_subscope_output_vars =
|
|
|
|
List.filter
|
2022-05-30 12:20:48 +03:00
|
|
|
(fun var_ctx -> Marked.unmark var_ctx.scope_var_io.Ast.io_output)
|
2022-05-04 18:40:55 +03:00
|
|
|
all_subscope_vars
|
|
|
|
in
|
|
|
|
let scope_dcalc_var = subscope_sig.scope_sig_scope_var in
|
|
|
|
let called_scope_input_struct = subscope_sig.scope_sig_input_struct in
|
|
|
|
let called_scope_return_struct = subscope_sig.scope_sig_output_struct in
|
|
|
|
let subscope_vars_defined =
|
2022-09-14 16:36:24 +03:00
|
|
|
try SubScopeMap.find subindex ctx.subscope_vars
|
2022-08-25 17:08:08 +03:00
|
|
|
with Not_found -> ScopeVarMap.empty
|
2022-05-04 18:40:55 +03:00
|
|
|
in
|
|
|
|
let subscope_var_not_yet_defined subvar =
|
2022-08-25 17:08:08 +03:00
|
|
|
not (ScopeVarMap.mem subvar subscope_vars_defined)
|
2022-05-04 18:40:55 +03:00
|
|
|
in
|
2022-08-17 18:14:29 +03:00
|
|
|
let pos_call = Marked.get_mark (SubScopeName.get_info subindex) in
|
2022-05-04 18:40:55 +03:00
|
|
|
let subscope_args =
|
|
|
|
List.map
|
|
|
|
(fun (subvar : scope_var_ctx) ->
|
|
|
|
if subscope_var_not_yet_defined subvar.scope_var_name then
|
2022-05-31 19:38:14 +03:00
|
|
|
(* This is a redundant check. Normally, all subscope variables
|
2022-05-04 18:40:55 +03:00
|
|
|
should have been defined (even an empty definition, if they're
|
|
|
|
not defined by any rule in the source code) by the translation
|
|
|
|
from desugared to the scope language. *)
|
2022-09-30 19:30:06 +03:00
|
|
|
Bindlib.box (Expr.empty_thunked_term m)
|
2022-05-04 18:40:55 +03:00
|
|
|
else
|
|
|
|
let a_var, _, _ =
|
2022-08-25 17:08:08 +03:00
|
|
|
ScopeVarMap.find subvar.scope_var_name subscope_vars_defined
|
2022-05-04 18:40:55 +03:00
|
|
|
in
|
2022-09-30 19:30:06 +03:00
|
|
|
Expr.make_var (a_var, mark_tany m pos_call))
|
2022-05-04 18:40:55 +03:00
|
|
|
all_subscope_input_vars
|
|
|
|
in
|
|
|
|
let subscope_struct_arg =
|
|
|
|
Bindlib.box_apply
|
|
|
|
(fun subscope_args ->
|
2022-08-12 23:42:39 +03:00
|
|
|
( ETuple (subscope_args, Some called_scope_input_struct),
|
2022-09-30 19:30:06 +03:00
|
|
|
mark_tany m pos_call ))
|
2022-05-04 18:40:55 +03:00
|
|
|
(Bindlib.box_list subscope_args)
|
|
|
|
in
|
|
|
|
let all_subscope_output_vars_dcalc =
|
|
|
|
List.map
|
|
|
|
(fun (subvar : scope_var_ctx) ->
|
|
|
|
let sub_dcalc_var =
|
2022-07-28 11:36:36 +03:00
|
|
|
Var.make
|
2022-08-17 18:14:29 +03:00
|
|
|
(Marked.unmark (SubScopeName.get_info subindex)
|
2022-06-03 17:40:03 +03:00
|
|
|
^ "."
|
2022-08-17 18:14:29 +03:00
|
|
|
^ Marked.unmark (ScopeVar.get_info subvar.scope_var_name))
|
2022-05-04 18:40:55 +03:00
|
|
|
in
|
2022-05-04 16:48:03 +03:00
|
|
|
subvar, sub_dcalc_var)
|
2022-05-04 18:40:55 +03:00
|
|
|
all_subscope_output_vars
|
|
|
|
in
|
|
|
|
let subscope_func =
|
|
|
|
tag_with_log_entry
|
2022-08-17 12:49:16 +03:00
|
|
|
(Expr.make_var
|
2022-09-30 19:30:06 +03:00
|
|
|
(scope_dcalc_var, mark_tany m pos_call))
|
2022-08-12 23:42:39 +03:00
|
|
|
BeginCall
|
2022-05-04 18:40:55 +03:00
|
|
|
[
|
2022-05-04 16:48:03 +03:00
|
|
|
sigma_name, pos_sigma;
|
2022-08-17 18:14:29 +03:00
|
|
|
SubScopeName.get_info subindex;
|
2022-08-12 23:42:39 +03:00
|
|
|
ScopeName.get_info subname;
|
2022-05-04 18:40:55 +03:00
|
|
|
]
|
|
|
|
in
|
|
|
|
let call_expr =
|
|
|
|
tag_with_log_entry
|
|
|
|
(Bindlib.box_apply2
|
2022-09-30 19:30:06 +03:00
|
|
|
(fun e u -> EApp (e, [u]), mark_tany m pos_call)
|
2022-05-04 18:40:55 +03:00
|
|
|
subscope_func subscope_struct_arg)
|
2022-08-12 23:42:39 +03:00
|
|
|
EndCall
|
2022-05-04 18:40:55 +03:00
|
|
|
[
|
2022-05-04 16:48:03 +03:00
|
|
|
sigma_name, pos_sigma;
|
2022-08-17 18:14:29 +03:00
|
|
|
SubScopeName.get_info subindex;
|
2022-08-12 23:42:39 +03:00
|
|
|
ScopeName.get_info subname;
|
2022-05-04 18:40:55 +03:00
|
|
|
]
|
|
|
|
in
|
2022-07-28 11:36:36 +03:00
|
|
|
let result_tuple_var = Var.make "result" in
|
2022-08-23 16:23:52 +03:00
|
|
|
let result_tuple_typ = TStruct called_scope_return_struct, pos_sigma in
|
2022-05-31 19:38:14 +03:00
|
|
|
let call_scope_let next =
|
2022-05-04 18:40:55 +03:00
|
|
|
Bindlib.box_apply2
|
|
|
|
(fun next call_expr ->
|
2022-08-12 23:42:39 +03:00
|
|
|
ScopeLet
|
2022-05-04 18:40:55 +03:00
|
|
|
{
|
2022-08-12 23:42:39 +03:00
|
|
|
scope_let_next = next;
|
|
|
|
scope_let_pos = pos_sigma;
|
|
|
|
scope_let_kind = CallingSubScope;
|
|
|
|
scope_let_typ = result_tuple_typ;
|
|
|
|
scope_let_expr = call_expr;
|
2022-05-04 18:40:55 +03:00
|
|
|
})
|
|
|
|
(Bindlib.bind_var result_tuple_var next)
|
|
|
|
call_expr
|
|
|
|
in
|
2022-05-31 19:38:14 +03:00
|
|
|
let result_bindings_lets next =
|
2022-05-04 18:40:55 +03:00
|
|
|
List.fold_right
|
|
|
|
(fun (var_ctx, v) (next, i) ->
|
|
|
|
( Bindlib.box_apply2
|
|
|
|
(fun next r ->
|
2022-08-12 23:42:39 +03:00
|
|
|
ScopeLet
|
2022-05-04 18:40:55 +03:00
|
|
|
{
|
2022-08-12 23:42:39 +03:00
|
|
|
scope_let_next = next;
|
|
|
|
scope_let_pos = pos_sigma;
|
|
|
|
scope_let_typ = var_ctx.scope_var_typ, pos_sigma;
|
2022-08-16 11:04:01 +03:00
|
|
|
scope_let_kind = DestructuringSubScopeResults;
|
2022-08-12 23:42:39 +03:00
|
|
|
scope_let_expr =
|
|
|
|
( ETupleAccess
|
2022-05-04 18:40:55 +03:00
|
|
|
( r,
|
|
|
|
i,
|
|
|
|
Some called_scope_return_struct,
|
|
|
|
List.map
|
|
|
|
(fun (var_ctx, _) ->
|
2022-05-04 16:48:03 +03:00
|
|
|
var_ctx.scope_var_typ, pos_sigma)
|
2022-05-04 18:40:55 +03:00
|
|
|
all_subscope_output_vars_dcalc ),
|
2022-09-30 19:30:06 +03:00
|
|
|
mark_tany m pos_sigma );
|
2022-05-04 18:40:55 +03:00
|
|
|
})
|
|
|
|
(Bindlib.bind_var v next)
|
2022-09-30 19:30:06 +03:00
|
|
|
(Expr.make_var (result_tuple_var, mark_tany m pos_sigma)),
|
2022-05-04 18:40:55 +03:00
|
|
|
i - 1 ))
|
|
|
|
all_subscope_output_vars_dcalc
|
|
|
|
(next, List.length all_subscope_output_vars_dcalc - 1)
|
|
|
|
in
|
|
|
|
( (fun next -> call_scope_let (fst (result_bindings_lets next))),
|
|
|
|
{
|
|
|
|
ctx with
|
|
|
|
subscope_vars =
|
2022-09-14 16:36:24 +03:00
|
|
|
SubScopeMap.add subindex
|
2022-05-04 18:40:55 +03:00
|
|
|
(List.fold_left
|
|
|
|
(fun acc (var_ctx, dvar) ->
|
2022-08-25 17:08:08 +03:00
|
|
|
ScopeVarMap.add var_ctx.scope_var_name
|
2022-05-04 18:40:55 +03:00
|
|
|
(dvar, var_ctx.scope_var_typ, var_ctx.scope_var_io)
|
|
|
|
acc)
|
2022-08-25 17:08:08 +03:00
|
|
|
ScopeVarMap.empty all_subscope_output_vars_dcalc)
|
2022-05-04 18:40:55 +03:00
|
|
|
ctx.subscope_vars;
|
|
|
|
} )
|
2020-12-10 20:11:43 +03:00
|
|
|
| Assertion e ->
|
2022-05-04 18:40:55 +03:00
|
|
|
let new_e = translate_expr ctx e in
|
|
|
|
( (fun next ->
|
|
|
|
Bindlib.box_apply2
|
|
|
|
(fun next new_e ->
|
2022-08-12 23:42:39 +03:00
|
|
|
ScopeLet
|
2022-05-04 18:40:55 +03:00
|
|
|
{
|
2022-08-12 23:42:39 +03:00
|
|
|
scope_let_next = next;
|
2022-08-26 16:21:47 +03:00
|
|
|
scope_let_pos = Expr.pos e;
|
|
|
|
scope_let_typ = TLit TUnit, Expr.pos e;
|
2022-08-12 23:42:39 +03:00
|
|
|
scope_let_expr =
|
2022-05-04 18:40:55 +03:00
|
|
|
(* To ensure that we throw an error if the value is not
|
|
|
|
defined, we add an check "ErrorOnEmpty" here. *)
|
2022-05-30 12:20:48 +03:00
|
|
|
Marked.same_mark_as
|
2022-08-26 16:21:47 +03:00
|
|
|
(EAssert (Marked.same_mark_as (ErrorOnEmpty new_e) e))
|
2022-05-04 18:40:55 +03:00
|
|
|
new_e;
|
2022-08-12 23:42:39 +03:00
|
|
|
scope_let_kind = Assertion;
|
2022-05-04 18:40:55 +03:00
|
|
|
})
|
2022-07-28 11:36:36 +03:00
|
|
|
(Bindlib.bind_var (Var.make "_") next)
|
2022-05-04 18:40:55 +03:00
|
|
|
new_e),
|
|
|
|
ctx )
|
2020-11-23 20:51:06 +03:00
|
|
|
|
2022-03-08 17:03:14 +03:00
|
|
|
let translate_rules
|
2022-09-23 18:43:48 +03:00
|
|
|
(ctx : 'm ctx)
|
|
|
|
(rules : 'm Ast.rule list)
|
2021-01-29 18:24:20 +03:00
|
|
|
((sigma_name, pos_sigma) : Utils.Uid.MarkedString.info)
|
2022-09-30 19:30:06 +03:00
|
|
|
(mark: 'm mark)
|
2022-08-12 23:42:39 +03:00
|
|
|
(sigma_return_struct_name : StructName.t) :
|
2022-09-23 18:43:48 +03:00
|
|
|
'm Dcalc.Ast.expr scope_body_expr Bindlib.box * 'm ctx =
|
2021-12-09 13:58:42 +03:00
|
|
|
let scope_lets, new_ctx =
|
2021-10-28 16:24:39 +03:00
|
|
|
List.fold_left
|
2021-12-09 13:58:42 +03:00
|
|
|
(fun (scope_lets, ctx) rule ->
|
2022-03-08 17:03:14 +03:00
|
|
|
let new_scope_lets, new_ctx =
|
|
|
|
translate_rule ctx rule (sigma_name, pos_sigma)
|
|
|
|
in
|
2022-05-04 16:48:03 +03:00
|
|
|
(fun next -> scope_lets (new_scope_lets next)), new_ctx)
|
2022-04-02 15:51:11 +03:00
|
|
|
((fun next -> next), ctx)
|
|
|
|
rules
|
2021-10-28 16:24:39 +03:00
|
|
|
in
|
2022-08-25 17:08:08 +03:00
|
|
|
let scope_variables = ScopeVarMap.bindings new_ctx.scope_vars in
|
2022-02-05 02:04:19 +03:00
|
|
|
let scope_output_variables =
|
2022-03-08 17:03:14 +03:00
|
|
|
List.filter
|
2022-05-30 12:20:48 +03:00
|
|
|
(fun (_, (_, _, io)) -> Marked.unmark io.Ast.io_output)
|
2022-03-08 17:03:14 +03:00
|
|
|
scope_variables
|
2022-02-05 02:04:19 +03:00
|
|
|
in
|
2021-10-28 16:24:39 +03:00
|
|
|
let return_exp =
|
2021-12-10 19:22:54 +03:00
|
|
|
Bindlib.box_apply
|
2022-03-08 17:03:14 +03:00
|
|
|
(fun args ->
|
2022-09-30 19:30:06 +03:00
|
|
|
ETuple (args, Some sigma_return_struct_name),
|
|
|
|
mark_tany mark pos_sigma)
|
2021-12-10 19:22:54 +03:00
|
|
|
(Bindlib.box_list
|
|
|
|
(List.map
|
2022-03-08 17:03:14 +03:00
|
|
|
(fun (_, (dcalc_var, _, _)) ->
|
2022-09-30 19:30:06 +03:00
|
|
|
Expr.make_var (dcalc_var, mark_tany mark pos_sigma))
|
2022-02-05 02:04:19 +03:00
|
|
|
scope_output_variables))
|
2021-10-28 16:24:39 +03:00
|
|
|
in
|
2022-04-02 15:51:11 +03:00
|
|
|
( scope_lets
|
2022-08-16 11:04:01 +03:00
|
|
|
(Bindlib.box_apply (fun return_exp -> Result return_exp) return_exp),
|
2022-04-02 15:51:11 +03:00
|
|
|
new_ctx )
|
2020-11-26 15:38:42 +03:00
|
|
|
|
2022-03-08 17:03:14 +03:00
|
|
|
let translate_scope_decl
|
2022-08-25 13:09:51 +03:00
|
|
|
(struct_ctx : struct_ctx)
|
|
|
|
(enum_ctx : enum_ctx)
|
2022-09-30 17:52:35 +03:00
|
|
|
(sctx : 'm scope_sigs_ctx)
|
2022-08-12 23:42:39 +03:00
|
|
|
(scope_name : ScopeName.t)
|
2022-09-23 18:43:48 +03:00
|
|
|
(sigma : 'm Ast.scope_decl) :
|
|
|
|
'm Dcalc.Ast.expr scope_body Bindlib.box * struct_ctx =
|
2022-08-12 23:42:39 +03:00
|
|
|
let sigma_info = ScopeName.get_info sigma.scope_decl_name in
|
2022-09-14 16:36:24 +03:00
|
|
|
let scope_sig = ScopeMap.find sigma.scope_decl_name sctx in
|
2022-01-31 20:09:14 +03:00
|
|
|
let scope_variables = scope_sig.scope_sig_local_vars in
|
2022-02-09 17:34:13 +03:00
|
|
|
let ctx =
|
2022-03-08 17:03:14 +03:00
|
|
|
(* the context must be initialized for fresh variables for all only-input
|
|
|
|
scope variables *)
|
2022-02-09 17:34:13 +03:00
|
|
|
List.fold_left
|
|
|
|
(fun ctx scope_var ->
|
2022-05-30 12:20:48 +03:00
|
|
|
match Marked.unmark scope_var.scope_var_io.io_input with
|
2022-02-09 17:34:13 +03:00
|
|
|
| OnlyInput ->
|
2022-08-17 18:14:29 +03:00
|
|
|
let scope_var_name = ScopeVar.get_info scope_var.scope_var_name in
|
2022-07-28 11:36:36 +03:00
|
|
|
let scope_var_dcalc = Var.make (Marked.unmark scope_var_name) in
|
2022-05-04 18:40:55 +03:00
|
|
|
{
|
|
|
|
ctx with
|
|
|
|
scope_vars =
|
2022-08-25 17:08:08 +03:00
|
|
|
ScopeVarMap.add scope_var.scope_var_name
|
2022-05-04 18:40:55 +03:00
|
|
|
( scope_var_dcalc,
|
|
|
|
scope_var.scope_var_typ,
|
|
|
|
scope_var.scope_var_io )
|
|
|
|
ctx.scope_vars;
|
|
|
|
}
|
2022-02-09 17:34:13 +03:00
|
|
|
| _ -> ctx)
|
|
|
|
(empty_ctx struct_ctx enum_ctx sctx scope_name)
|
|
|
|
scope_variables
|
|
|
|
in
|
2022-01-31 20:09:14 +03:00
|
|
|
let scope_input_var = scope_sig.scope_sig_input_var in
|
|
|
|
let scope_input_struct_name = scope_sig.scope_sig_input_struct in
|
|
|
|
let scope_return_struct_name = scope_sig.scope_sig_output_struct in
|
2022-05-30 12:20:48 +03:00
|
|
|
let pos_sigma = Marked.get_mark sigma_info in
|
2022-04-02 15:51:11 +03:00
|
|
|
let rules_with_return_expr, ctx =
|
2022-09-30 19:30:06 +03:00
|
|
|
translate_rules ctx sigma.scope_decl_rules sigma_info sigma.scope_mark
|
2022-03-08 17:03:14 +03:00
|
|
|
scope_return_struct_name
|
2021-12-09 13:58:42 +03:00
|
|
|
in
|
2020-11-27 13:37:21 +03:00
|
|
|
let scope_variables =
|
|
|
|
List.map
|
2022-01-31 20:09:14 +03:00
|
|
|
(fun var_ctx ->
|
2022-03-08 17:03:14 +03:00
|
|
|
let dcalc_x, _, _ =
|
2022-08-25 17:08:08 +03:00
|
|
|
ScopeVarMap.find var_ctx.scope_var_name ctx.scope_vars
|
2022-03-08 17:03:14 +03:00
|
|
|
in
|
2022-05-04 16:48:03 +03:00
|
|
|
var_ctx, dcalc_x)
|
2020-11-27 13:37:21 +03:00
|
|
|
scope_variables
|
|
|
|
in
|
2021-02-01 17:57:19 +03:00
|
|
|
(* first we create variables from the fields of the input struct *)
|
2022-02-05 02:04:19 +03:00
|
|
|
let scope_input_variables =
|
2022-02-07 12:30:36 +03:00
|
|
|
List.filter
|
|
|
|
(fun (var_ctx, _) ->
|
2022-05-30 12:20:48 +03:00
|
|
|
match Marked.unmark var_ctx.scope_var_io.io_input with
|
2022-03-08 17:03:14 +03:00
|
|
|
| NoInput -> false
|
|
|
|
| _ -> true)
|
2022-02-07 12:30:36 +03:00
|
|
|
scope_variables
|
2022-02-05 02:04:19 +03:00
|
|
|
in
|
|
|
|
let scope_output_variables =
|
2022-03-08 17:03:14 +03:00
|
|
|
List.filter
|
2022-05-30 12:20:48 +03:00
|
|
|
(fun (var_ctx, _) -> Marked.unmark var_ctx.scope_var_io.io_output)
|
2022-03-08 17:03:14 +03:00
|
|
|
scope_variables
|
2022-02-05 02:04:19 +03:00
|
|
|
in
|
2022-02-09 17:34:13 +03:00
|
|
|
let input_var_typ (var_ctx : scope_var_ctx) =
|
2022-05-30 12:20:48 +03:00
|
|
|
match Marked.unmark var_ctx.scope_var_io.io_input with
|
2022-05-04 16:48:03 +03:00
|
|
|
| OnlyInput -> var_ctx.scope_var_typ, pos_sigma
|
2022-02-09 17:34:13 +03:00
|
|
|
| Reentrant ->
|
2022-08-16 11:04:01 +03:00
|
|
|
( TArrow ((TLit TUnit, pos_sigma), (var_ctx.scope_var_typ, pos_sigma)),
|
2022-05-04 18:40:55 +03:00
|
|
|
pos_sigma )
|
2022-02-09 17:34:13 +03:00
|
|
|
| NoInput -> failwith "should not happen"
|
|
|
|
in
|
2022-05-31 19:38:14 +03:00
|
|
|
let input_destructurings next =
|
2022-04-02 15:51:11 +03:00
|
|
|
fst
|
|
|
|
(List.fold_right
|
|
|
|
(fun (var_ctx, v) (next, i) ->
|
|
|
|
( Bindlib.box_apply2
|
|
|
|
(fun next r ->
|
2022-08-12 23:42:39 +03:00
|
|
|
ScopeLet
|
2022-04-02 15:51:11 +03:00
|
|
|
{
|
2022-08-16 11:04:01 +03:00
|
|
|
scope_let_kind = DestructuringInputStruct;
|
2022-08-12 23:42:39 +03:00
|
|
|
scope_let_next = next;
|
|
|
|
scope_let_pos = pos_sigma;
|
|
|
|
scope_let_typ = input_var_typ var_ctx;
|
|
|
|
scope_let_expr =
|
|
|
|
( ETupleAccess
|
2022-04-02 15:51:11 +03:00
|
|
|
( r,
|
|
|
|
i,
|
|
|
|
Some scope_input_struct_name,
|
|
|
|
List.map
|
|
|
|
(fun (var_ctx, _) -> input_var_typ var_ctx)
|
|
|
|
scope_input_variables ),
|
2022-09-30 19:30:06 +03:00
|
|
|
mark_tany sigma.scope_mark pos_sigma );
|
2022-04-02 15:51:11 +03:00
|
|
|
})
|
|
|
|
(Bindlib.bind_var v next)
|
2022-09-30 19:30:06 +03:00
|
|
|
(Expr.make_var (scope_input_var, mark_tany sigma.scope_mark pos_sigma)),
|
2022-04-02 15:51:11 +03:00
|
|
|
i - 1 ))
|
|
|
|
scope_input_variables
|
|
|
|
(next, List.length scope_input_variables - 1))
|
2021-02-01 17:57:19 +03:00
|
|
|
in
|
2021-01-29 18:24:20 +03:00
|
|
|
let scope_return_struct_fields =
|
|
|
|
List.map
|
2022-01-31 20:09:14 +03:00
|
|
|
(fun (var_ctx, dvar) ->
|
2021-02-01 17:57:19 +03:00
|
|
|
let struct_field_name =
|
2022-08-12 23:42:39 +03:00
|
|
|
StructFieldName.fresh (Bindlib.name_of dvar ^ "_out", pos_sigma)
|
2021-02-01 17:57:19 +03:00
|
|
|
in
|
2022-05-04 16:48:03 +03:00
|
|
|
struct_field_name, (var_ctx.scope_var_typ, pos_sigma))
|
2022-02-05 02:04:19 +03:00
|
|
|
scope_output_variables
|
2021-01-29 18:24:20 +03:00
|
|
|
in
|
2021-02-01 17:57:19 +03:00
|
|
|
let scope_input_struct_fields =
|
|
|
|
List.map
|
2022-01-31 20:09:14 +03:00
|
|
|
(fun (var_ctx, dvar) ->
|
2021-02-01 17:57:19 +03:00
|
|
|
let struct_field_name =
|
2022-08-12 23:42:39 +03:00
|
|
|
StructFieldName.fresh (Bindlib.name_of dvar ^ "_in", pos_sigma)
|
2021-02-01 17:57:19 +03:00
|
|
|
in
|
2022-05-04 16:48:03 +03:00
|
|
|
struct_field_name, input_var_typ var_ctx)
|
2022-02-05 02:04:19 +03:00
|
|
|
scope_input_variables
|
2021-02-01 17:57:19 +03:00
|
|
|
in
|
2021-01-29 18:24:20 +03:00
|
|
|
let new_struct_ctx =
|
2022-08-12 23:42:39 +03:00
|
|
|
StructMap.add scope_input_struct_name scope_input_struct_fields
|
2022-08-16 11:04:01 +03:00
|
|
|
(StructMap.singleton scope_return_struct_name scope_return_struct_fields)
|
2021-01-29 18:24:20 +03:00
|
|
|
in
|
2022-04-02 15:51:11 +03:00
|
|
|
( Bindlib.box_apply
|
|
|
|
(fun scope_body_expr ->
|
|
|
|
{
|
2022-08-12 23:42:39 +03:00
|
|
|
scope_body_expr;
|
|
|
|
scope_body_input_struct = scope_input_struct_name;
|
|
|
|
scope_body_output_struct = scope_return_struct_name;
|
2022-04-02 15:51:11 +03:00
|
|
|
})
|
|
|
|
(Bindlib.bind_var scope_input_var
|
|
|
|
(input_destructurings rules_with_return_expr)),
|
2021-01-29 18:24:20 +03:00
|
|
|
new_struct_ctx )
|
2020-11-27 13:37:21 +03:00
|
|
|
|
2022-09-30 17:52:35 +03:00
|
|
|
let translate_program (prgm : 'm Ast.program) : 'm Dcalc.Ast.program =
|
2020-11-25 20:00:34 +03:00
|
|
|
let scope_dependencies = Dependency.build_program_dep_graph prgm in
|
2020-12-06 14:32:36 +03:00
|
|
|
Dependency.check_for_cycle_in_scope scope_dependencies;
|
2020-11-25 20:00:34 +03:00
|
|
|
let scope_ordering = Dependency.get_scope_ordering scope_dependencies in
|
2022-08-25 13:09:51 +03:00
|
|
|
let decl_ctx = prgm.program_ctx in
|
2022-09-30 17:52:35 +03:00
|
|
|
let sctx : 'm scope_sigs_ctx =
|
2022-09-14 16:36:24 +03:00
|
|
|
ScopeMap.mapi
|
2020-12-10 18:58:32 +03:00
|
|
|
(fun scope_name scope ->
|
2022-03-08 17:03:14 +03:00
|
|
|
let scope_dvar =
|
2022-07-28 11:36:36 +03:00
|
|
|
Var.make
|
2022-08-12 23:42:39 +03:00
|
|
|
(Marked.unmark (ScopeName.get_info scope.Ast.scope_decl_name))
|
2022-03-08 17:03:14 +03:00
|
|
|
in
|
2021-01-29 18:24:20 +03:00
|
|
|
let scope_return_struct_name =
|
2022-08-12 23:42:39 +03:00
|
|
|
StructName.fresh
|
2022-05-30 12:20:48 +03:00
|
|
|
(Marked.map_under_mark
|
2022-03-08 17:03:14 +03:00
|
|
|
(fun s -> s ^ "_out")
|
2022-08-12 23:42:39 +03:00
|
|
|
(ScopeName.get_info scope_name))
|
2021-01-29 18:24:20 +03:00
|
|
|
in
|
2021-02-01 17:57:19 +03:00
|
|
|
let scope_input_var =
|
2022-08-12 23:42:39 +03:00
|
|
|
Var.make (Marked.unmark (ScopeName.get_info scope_name) ^ "_in")
|
2021-02-01 17:57:19 +03:00
|
|
|
in
|
|
|
|
let scope_input_struct_name =
|
2022-08-12 23:42:39 +03:00
|
|
|
StructName.fresh
|
2022-05-30 12:20:48 +03:00
|
|
|
(Marked.map_under_mark
|
2022-03-08 17:03:14 +03:00
|
|
|
(fun s -> s ^ "_in")
|
2022-08-12 23:42:39 +03:00
|
|
|
(ScopeName.get_info scope_name))
|
2021-02-01 17:57:19 +03:00
|
|
|
in
|
2022-01-31 20:09:14 +03:00
|
|
|
{
|
|
|
|
scope_sig_local_vars =
|
|
|
|
List.map
|
2022-02-04 16:34:25 +03:00
|
|
|
(fun (scope_var, (tau, vis)) ->
|
2022-03-08 17:03:14 +03:00
|
|
|
{
|
|
|
|
scope_var_name = scope_var;
|
2022-05-30 12:20:48 +03:00
|
|
|
scope_var_typ = Marked.unmark tau;
|
2022-03-08 17:03:14 +03:00
|
|
|
scope_var_io = vis;
|
|
|
|
})
|
2022-08-25 17:08:08 +03:00
|
|
|
(ScopeVarMap.bindings scope.scope_sig);
|
2022-01-31 20:09:14 +03:00
|
|
|
scope_sig_scope_var = scope_dvar;
|
|
|
|
scope_sig_input_var = scope_input_var;
|
|
|
|
scope_sig_input_struct = scope_input_struct_name;
|
|
|
|
scope_sig_output_struct = scope_return_struct_name;
|
|
|
|
})
|
2020-12-04 18:40:17 +03:00
|
|
|
prgm.program_scopes
|
2020-11-27 13:37:21 +03:00
|
|
|
in
|
2022-03-08 17:03:14 +03:00
|
|
|
(* the resulting expression is the list of definitions of all the scopes,
|
|
|
|
ending with the top-level scope. *)
|
2022-09-30 17:52:35 +03:00
|
|
|
let (scopes, decl_ctx) : 'm Dcalc.Ast.expr scopes Bindlib.box * _ =
|
2021-01-28 15:58:59 +03:00
|
|
|
List.fold_right
|
2022-04-04 09:56:48 +03:00
|
|
|
(fun scope_name (scopes, decl_ctx) ->
|
2022-09-14 16:36:24 +03:00
|
|
|
let scope = ScopeMap.find scope_name prgm.program_scopes in
|
2021-12-09 01:56:03 +03:00
|
|
|
let scope_body, scope_out_struct =
|
2022-08-25 13:09:51 +03:00
|
|
|
translate_scope_decl decl_ctx.ctx_structs decl_ctx.ctx_enums sctx
|
|
|
|
scope_name scope
|
2021-01-29 18:24:20 +03:00
|
|
|
in
|
2022-09-14 16:36:24 +03:00
|
|
|
let dvar = (ScopeMap.find scope_name sctx).scope_sig_scope_var in
|
2021-01-29 18:24:20 +03:00
|
|
|
let decl_ctx =
|
|
|
|
{
|
|
|
|
decl_ctx with
|
2022-08-12 23:42:39 +03:00
|
|
|
ctx_structs =
|
|
|
|
StructMap.union
|
2021-01-29 18:24:20 +03:00
|
|
|
(fun _ _ -> assert false (* should not happen *))
|
2022-08-12 23:42:39 +03:00
|
|
|
decl_ctx.ctx_structs scope_out_struct;
|
2021-01-29 18:24:20 +03:00
|
|
|
}
|
|
|
|
in
|
2022-04-04 09:56:48 +03:00
|
|
|
let scope_next = Bindlib.bind_var dvar scopes in
|
|
|
|
let new_scopes =
|
|
|
|
Bindlib.box_apply2
|
|
|
|
(fun scope_body scope_next ->
|
2022-08-12 23:42:39 +03:00
|
|
|
ScopeDef { scope_name; scope_body; scope_next })
|
2022-04-04 09:56:48 +03:00
|
|
|
scope_body scope_next
|
|
|
|
in
|
2022-05-04 16:48:03 +03:00
|
|
|
new_scopes, decl_ctx)
|
2022-04-04 09:56:48 +03:00
|
|
|
scope_ordering
|
2022-08-12 23:42:39 +03:00
|
|
|
(Bindlib.box Nil, decl_ctx)
|
2021-01-28 15:58:59 +03:00
|
|
|
in
|
2022-09-27 19:45:22 +03:00
|
|
|
{ scopes = Bindlib.unbox scopes; decl_ctx }
|