package catala
Install
Dune Dependency
Authors
Maintainers
Sources
md5=6dbbc2f50c23693f26ab6f048e78172f
sha512=a5701e14932d8a866e2aa3731f76df85ff2a68b4fa943fd510c535913573274d66eaec1ae6fcae17f20b475876048a9ab196ef6d8c23d4ea6b90b986aa0a6daa
doc/catala.dcalc/Dcalc/Ast/index.html
Module Dcalc.Ast
Source
Abstract syntax tree of the default calculus intermediate representation
Abstract syntax tree for the default calculus
Abstract syntax tree
and typ =
| TLit of typ_lit
| TTuple of marked_typ list * StructName.t option
| TEnum of marked_typ list * EnumName.t
| TArrow of marked_typ * marked_typ
| TArray of marked_typ
| TAny
type lit =
| LBool of bool
| LEmptyError
| LInt of Runtime.integer
| LRat of Runtime.decimal
| LMoney of Runtime.money
| LUnit
| LDate of date
| LDuration of duration
type unop =
| Not
| Minus of op_kind
| Log of log_entry * Utils.Uid.MarkedString.info list
| Length
| IntToRat
| MoneyToRat
| RatToMoney
| GetDay
| GetMonth
| GetYear
| FirstDayOfMonth
| LastDayOfMonth
| RoundMoney
| RoundDecimal
The generic type of AST markings. Using a GADT allows functions to be polymorphic in the marking, but still do transformations on types when appropriate
and 'm expr =
| EVar of 'm expr Bindlib.var
| ETuple of 'm marked_expr list * StructName.t option
(*The
*)MarkedString.info
is the former struct field name| ETupleAccess of 'm marked_expr * int * StructName.t option * marked_typ list
(*The
*)MarkedString.info
is the former struct field name| EInj of 'm marked_expr * int * EnumName.t * marked_typ list
(*The
*)MarkedString.info
is the former enum case name| EMatch of 'm marked_expr * 'm marked_expr list * EnumName.t
(*The
*)MarkedString.info
is the former enum case name| EArray of 'm marked_expr list
| ELit of lit
| EAbs of ('m expr, 'm marked_expr) Bindlib.mbinder * marked_typ list
| EApp of 'm marked_expr * 'm marked_expr list
| EAssert of 'm marked_expr
| EOp of operator
| EDefault of 'm marked_expr list * 'm marked_expr * 'm marked_expr
| EIfThenElse of 'm marked_expr * 'm marked_expr * 'm marked_expr
| ErrorOnEmpty of 'm marked_expr
The expressions use the Bindlib library, based on higher-order abstract syntax
Expression annotations (Marked.t
)
type scope_let_kind =
| DestructuringInputStruct
(*
*)let x = input.field
| ScopeVarDefinition
(*
*)let x = error_on_empty e
| SubScopeVarDefinition
(*
*)let s.x = fun _ -> e
orlet s.x = error_on_empty e
for input-only subscope variables.| CallingSubScope
(*
*)let result = s ({ x = s.x; y = s.x; ...})
| DestructuringSubScopeResults
(*
*)let s.x = result.x
*| Assertion
(*
*)let _ = assert e
This kind annotation signals that the let-binding respects a structural invariant. These invariants concern the shape of the expression in the let-binding, and are documented below.
type ('expr, 'm) scope_let = {
scope_let_kind : scope_let_kind;
scope_let_typ : marked_typ;
scope_let_expr : ('expr, 'm) marked;
scope_let_next : ('expr, ('expr, 'm) scope_body_expr) Bindlib.binder;
scope_let_pos : Utils.Pos.t;
}
This type is parametrized by the expression type so it can be reused in later intermediate representations.
A scope let-binding has all the information necessary to make a proper let-binding expression, plus an annotation for the kind of the let-binding that comes from the compilation of a Scopelang.Ast
statement.
type ('expr, 'm) scope_body = {
scope_body_input_struct : StructName.t;
scope_body_output_struct : StructName.t;
scope_body_expr : ('expr, ('expr, 'm) scope_body_expr) Bindlib.binder;
}
Instead of being a single expression, we give a little more ad-hoc structure to the scope body by decomposing it in an ordered list of let-bindings, and a result expression that uses the let-binded variables. The first binder is the argument of type scope_body_input_struct
.
type ('expr, 'm) scope_def = {
scope_name : ScopeName.t;
scope_body : ('expr, 'm) scope_body;
scope_next : ('expr, ('expr, 'm) scopes) Bindlib.binder;
}
Finally, we do the same transformation for the whole program for the kinded lets. This permit us to use bindlib variables for scopes names.
Helpers
Manipulation of marks
All the following functions will resolve the types if called on an Inferring
type
val map_mark :
(Utils.Pos.t -> Utils.Pos.t) ->
(marked_typ -> marked_typ) ->
'm mark ->
'm mark
val map_mark2 :
(Utils.Pos.t -> Utils.Pos.t -> Utils.Pos.t) ->
(typed -> typed -> marked_typ) ->
'm mark ->
'm mark ->
'm mark
val fold_marks :
(Utils.Pos.t list -> Utils.Pos.t) ->
(typed list -> marked_typ) ->
'm mark list ->
'm mark
Boxed constructors
val etuple :
'm marked_expr Bindlib.box list ->
StructName.t option ->
'm mark ->
'm marked_expr Bindlib.box
val etupleaccess :
'm marked_expr Bindlib.box ->
int ->
StructName.t option ->
marked_typ list ->
'm mark ->
'm marked_expr Bindlib.box
val einj :
'm marked_expr Bindlib.box ->
int ->
EnumName.t ->
marked_typ list ->
'm mark ->
'm marked_expr Bindlib.box
val ematch :
'm marked_expr Bindlib.box ->
'm marked_expr Bindlib.box list ->
EnumName.t ->
'm mark ->
'm marked_expr Bindlib.box
val eabs :
('m expr, 'm marked_expr) Bindlib.mbinder Bindlib.box ->
marked_typ list ->
'm mark ->
'm marked_expr Bindlib.box
val eapp :
'm marked_expr Bindlib.box ->
'm marked_expr Bindlib.box list ->
'm mark ->
'm marked_expr Bindlib.box
val edefault :
'm marked_expr Bindlib.box list ->
'm marked_expr Bindlib.box ->
'm marked_expr Bindlib.box ->
'm mark ->
'm marked_expr Bindlib.box
val eifthenelse :
'm marked_expr Bindlib.box ->
'm marked_expr Bindlib.box ->
'm marked_expr Bindlib.box ->
'm mark ->
'm marked_expr Bindlib.box
Program traversal
Be careful when using these traversal functions, as the bound variables they open will be different at each traversal.
val map_expr :
'a ->
f:('a -> 'm1 marked_expr -> 'm2 marked_expr Bindlib.box) ->
('m1 expr, 'm2 mark) Utils.Marked.t ->
'm2 marked_expr Bindlib.box
If you want to apply a map transform to an expression, you can save up writing a painful match over all the cases of the AST. For instance, if you want to remove all errors on empty, you can write
let remove_error_empty =
let rec f () e =
match Marked.unmark e with
| ErrorOnEmpty e1 -> map_expr () f e1
| _ -> map_expr () f e
in
f () e
The first argument of map_expr is an optional context that you can carry around during your map traversal.
val map_expr_top_down :
f:('m1 marked_expr -> ('m1 expr, 'm2 mark) Utils.Marked.t) ->
'm1 marked_expr ->
'm2 marked_expr Bindlib.box
Recursively applies f
to the nodes of the expression tree. The type returned by f
is hybrid since the mark at top-level has been rewritten, but not yet the marks in the subtrees.
val map_expr_marks :
f:('m1 mark -> 'm2 mark) ->
'm1 marked_expr ->
'm2 marked_expr Bindlib.box
val fold_left_scope_lets :
f:('a -> ('expr, 'm) scope_let -> 'expr Bindlib.var -> 'a) ->
init:'a ->
('expr, 'm) scope_body_expr ->
'a
Usage: fold_left_scope_lets ~f:(fun acc scope_let scope_let_var -> ...) ~init scope_lets
, where scope_let_var
is the variable bound to the scope let in the next scope lets to be examined.
val fold_right_scope_lets :
f:(('expr1, 'm1) scope_let -> 'expr1 Bindlib.var -> 'a -> 'a) ->
init:(('expr1, 'm1) marked -> 'a) ->
('expr1, 'm1) scope_body_expr ->
'a
Usage: fold_right_scope_lets ~f:(fun scope_let scope_let_var acc -> ...) ~init scope_lets
, where scope_let_var
is the variable bound to the scope let in the next scope lets to be examined (which are before in the program order).
val map_exprs_in_scope_lets :
f:(('expr1, 'm1) marked -> ('expr2, 'm2) marked Bindlib.box) ->
varf:('expr1 Bindlib.var -> 'expr2 Bindlib.var) ->
('expr1, 'm1) scope_body_expr ->
('expr2, 'm2) scope_body_expr Bindlib.box
val fold_left_scope_defs :
f:('a -> ('expr1, 'm1) scope_def -> 'expr1 Bindlib.var -> 'a) ->
init:'a ->
('expr1, 'm1) scopes ->
'a
Usage: fold_left_scope_defs ~f:(fun acc scope_def scope_var -> ...) ~init scope_def
, where scope_var
is the variable bound to the scope in the next scopes to be examined.
val fold_right_scope_defs :
f:(('expr1, 'm1) scope_def -> 'expr1 Bindlib.var -> 'a -> 'a) ->
init:'a ->
('expr1, 'm1) scopes ->
'a
Usage: fold_right_scope_defs ~f:(fun scope_def scope_var acc -> ...) ~init scope_def
, where scope_var
is the variable bound to the scope in the next scopes to be examined (which are before in the program order).
val map_scope_defs :
f:(('expr, 'm) scope_def -> ('expr, 'm) scope_def Bindlib.box) ->
('expr, 'm) scopes ->
('expr, 'm) scopes Bindlib.box
val map_exprs_in_scopes :
f:(('expr1, 'm1) marked -> ('expr2, 'm2) marked Bindlib.box) ->
varf:('expr1 Bindlib.var -> 'expr2 Bindlib.var) ->
('expr1, 'm1) scopes ->
('expr2, 'm2) scopes Bindlib.box
This is the main map visitor for all the expressions inside all the scopes of the program.
Variables
used to convert between e.g. untyped expr var
into a typed expr var
Boxed term constructors
type ('e, 'm) make_abs_sig =
'e Bindlib.mvar ->
('e, 'm) marked Bindlib.box ->
marked_typ list ->
'm mark ->
('e, 'm) marked Bindlib.box
val make_app :
'm marked_expr Bindlib.box ->
'm marked_expr Bindlib.box list ->
'm mark ->
'm marked_expr Bindlib.box
type ('expr, 'm) make_let_in_sig =
'expr Bindlib.var ->
marked_typ ->
('expr, 'm) marked Bindlib.box ->
('expr, 'm) marked Bindlib.box ->
Utils.Pos.t ->
('expr, 'm) marked Bindlib.box
Other
Determines if two expressions are equal, omitting their position information
AST manipulation helpers
val build_whole_scope_expr :
box_expr:('expr, 'm) box_expr_sig ->
make_abs:('expr, 'm) make_abs_sig ->
make_let_in:('expr, 'm) make_let_in_sig ->
decl_ctx ->
('expr, 'm) scope_body ->
'm mark ->
('expr, 'm) marked Bindlib.box
Usage: build_whole_scope_expr ctx body scope_position
where scope_position
corresponds to the line of the scope declaration for instance.
val unfold_scopes :
box_expr:('expr, 'm) box_expr_sig ->
make_abs:('expr, 'm) make_abs_sig ->
make_let_in:('expr, 'm) make_let_in_sig ->
decl_ctx ->
('expr, 'm) scopes ->
'm mark ->
'expr scope_name_or_var ->
('expr, 'm) marked Bindlib.box
val build_whole_program_expr :
box_expr:('expr, 'm) box_expr_sig ->
make_abs:('expr, 'm) make_abs_sig ->
make_let_in:('expr, 'm) make_let_in_sig ->
('expr, 'm) program_generic ->
ScopeName.t ->
('expr, 'm) marked Bindlib.box
Usage: build_whole_program_expr program main_scope
builds an expression corresponding to the main program and returning the main scope as a function.
Used by the optimizer to know when to stop
Removes all calls to Log
unary operators in the AST, replacing them by their argument.
val build_scope_typ_from_sig :
decl_ctx ->
StructName.t ->
StructName.t ->
Utils.Pos.t ->
typ Utils.Marked.pos
build_scope_typ_from_sig ctx in_struct out_struct pos
builds the arrow type for the specified scope