123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173(* This file is part of the Catala compiler, a specification language for tax
and social benefits computation rules. Copyright (C) 2020 Inria, contributor:
Alain Delaët-Tixeuil <alain.delaet--tixeuil@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. *)openCatala_utilsopenShared_astmoduleD=Dcalc.AstmoduleA=Ast(** We make use of the strong invariants on the structure of programs:
Defaultable values can only appear in certain positions. This information is
given by the type structure of expressions. In particular this mean we don't
need to use the monadic bind while computing arithmetic operations or
function calls. The resulting function is not more difficult than what we
had when translating without exceptions.
The typing translation is to simply transform default type into option
types. *)lettranslate_typ(tau:typ):typ=letrecaux=function|TDefault((_,pos2)ast),pos1->Bindlib.box_apply(funt->TOption(TTuple[t;TLitTPos,pos2],pos2),pos1)(auxt)|TClosureEnv,pos->Message.error~internal:true~pos"The type closure_env should not appear before the dcalc -> lcalc \
translation step."|t->Type.mapauxtinBindlib.unbox(auxtau)lettranslate_markm=Expr.map_tytranslate_typmletrectranslate_default(exceptions:'mD.exprlist)(just:'mD.expr)(cons:'mD.expr)(mark_default:'mmark):'mA.exprboxed=(* Since the program is well typed, all exceptions have as type [option ('t *
pos)] *)letpos=Expr.mark_posmark_defaultinletty_option=Expr.maybe_tymark_defaultinletty_array=TArrayty_option,posinletty_alpha=matchty_optionwith|TOptionty,_->ty|(TVar_,_)asty->ty|_->assertfalseinletmark_alpha=Expr.with_tymark_defaultty_alphainletif_just_then_cons=letnone=Expr.einj~cons:Expr.none_constr~name:Expr.option_enum~e:(Expr.elitLUnit(Expr.with_tymark_default(TLitTUnit,pos)))mark_defaultinmatchjustwith|ELit(LBoolb),_->ifbthentranslate_exprconselsenone|just->Expr.eifthenelse(translate_exprjust)(translate_exprcons)(Expr.einj~e:(Expr.elitLUnit(Expr.with_tymark_default(TLitTUnit,pos)))~cons:Expr.none_constr~name:Expr.option_enummark_default)mark_defaultinletmatch_somee=matchjustwith|ELit(LBoolfalse),_->(* in this case we can just forward the option in the argument *)e|_->Expr.ematch~name:Expr.option_enum~e~cases:(EnumConstructor.Map.of_list[(* Some x -> Some x *)(Expr.some_constr,letx=Var.make"x"inExpr.make_ghost_abs[x](Expr.einj~name:Expr.option_enum~cons:Expr.some_constr~e:(Expr.evarxmark_alpha)mark_default)[ty_alpha]pos);(* None -> if just then cons else None *)Expr.none_constr,Expr.thunk_termif_just_then_cons;])mark_defaultinmatchexceptionswith|[]->if_just_then_cons|[((EInj{cons;_},_)ase)]->ifEnumConstructor.equalconsExpr.none_constrthenExpr.thunk_termif_just_then_conselseifEnumConstructor.equalconsExpr.some_constrthentranslate_expreelseassertfalse|[single_exception]->match_some(translate_exprsingle_exception)|exceptions->letexceptions=List.maptranslate_exprexceptionsinmatch_some(Expr.eappop~op:(Op.HandleExceptions,Expr.poscons)~tys:[ty_array]~args:[Expr.earrayexceptions(Expr.with_tymark_defaultty_array)]mark_default)andtranslate_expr(e:'mD.expr):'mA.exprboxed=matchewith|EEmpty,m->letm=translate_markminletpos=Expr.mark_posminExpr.einj~e:(Expr.elitLUnit(Expr.with_tym(TLitTUnit,pos)))~cons:Expr.none_constr~name:Expr.option_enumm|EErrorOnEmptyarg,m->letm=translate_markminletpos=Expr.mark_posminletm_pos_pair=Expr.map_ty(funty->TTuple[ty;TLitTPos,pos],pos)minletcases=EnumConstructor.Map.of_list[(Expr.none_constr,letx=Var.make"_"inExpr.make_ghost_abs[x](Expr.efatalerrorNoValuem)[TLitTUnit,pos]pos);(* | None x -> raise NoValueProvided *)(Expr.some_constr,letvar=Var.make"arg"inExpr.make_abs[var,pos](Expr.make_tupleaccess(Expr.evarvarm_pos_pair)02pos)[Expr.maybe_tym_pos_pair]pos);]inExpr.ematch~e:(translate_exprarg)~name:Expr.option_enum~casesm|EDefault{excepts;just;cons},m->translate_defaultexceptsjustcons(translate_markm)|EPureDefaulte,m->letpos=Expr.mark_posminlete=Expr.make_tuple[translate_expre;Expr.make_posposm]minExpr.einj~e~cons:Expr.some_constr~name:Expr.option_enum(translate_markm)|EAppOp{op;tys;args},m->Expr.eappop~op:(Operator.translateop)~tys:(List.maptranslate_typtys)~args:(List.maptranslate_exprargs)(translate_markm)|((ELit_|EArray_|EVar_|EApp_|EAbs_|EExternal_|EIfThenElse_|ETuple_|ETupleAccess_|EInj_|EAssert_|EFatalError_|EStruct_|EStructAccess_|EMatch_|EPos_),_)ase->Expr.map~f:translate_expr~typ:translate_type|_->.lettranslate_program(prg:'mD.program):'mA.program=Program.map_exprsprg~typ:translate_typ~varf:Var.translate~f:translate_expr