Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(compiler): Compiling Dcalc into Lcalc without using ∅ errors #158

Merged
merged 108 commits into from
Feb 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
108 commits
Select commit Hold shift + click to select a range
6fdd739
saving my work somewhere
Nov 2, 2021
a24a4ab
starting to work on type inference
Nov 3, 2021
41a8961
tentative, trying something else
Nov 4, 2021
0f5fde2
advancing
Nov 4, 2021
53b4012
should be ok, without handling the types
Nov 22, 2021
f75341c
making options default compilation target
Nov 9, 2021
08b3847
found a bug inside the match translation.
Nov 22, 2021
949df1c
the translation executes correctly, but the result is totally unreadable
Nov 24, 2021
fb281a0
Formatting
denismerigoux Nov 24, 2021
7d3e381
Improvements with Alain during weekly meeting
denismerigoux Nov 24, 2021
3d2f963
add marking in the position utils. This replace the internal-based mo…
Nov 25, 2021
7ec067c
added mockup of eoption in the ocaml runtime
Nov 25, 2021
fcdaa21
add utilities that replace to deal with options
Nov 25, 2021
3bc71e8
modification to take into account the prevous commit
Nov 25, 2021
c2db3a4
ref: use of built-in match instead of matchopt (wip)
Nov 26, 2021
cf43e3d
add generic identity optimization helper
Nov 29, 2021
22af2a9
refactored transformation to remove matchopt construction
Nov 29, 2021
8d580f1
fix: removed ESome and ENone constructions.
Nov 29, 2021
536dde9
Formatting + CI + etc
denismerigoux Nov 30, 2021
c3bde49
Merge branch 'master' into alain_default-option
denismerigoux Nov 30, 2021
604fbbf
Stub of changing signature
denismerigoux Nov 30, 2021
76f5e61
changing signature -- cont
Nov 30, 2021
fd8ff75
renamed transform -> visitor_map
Dec 1, 2021
be166eb
add lazy implementation of handle_default_opt in runtime
Dec 1, 2021
5f86837
correct use of bindlib in the translation
Dec 1, 2021
3f8bc48
add refine iota transformation in lcalc
Dec 1, 2021
86fa2ea
correct bindlib utilization (cont)
Dec 1, 2021
0dfac82
fix invariant correction within ErrorOnEmpty
Dec 1, 2021
ac7df6c
add: implementation of generic operator without the need of rewriting…
Dec 1, 2021
959203e
add: error message when unary operator log is left somewhere it shoul…
Dec 1, 2021
52aae25
bump version
Dec 1, 2021
177a214
handle_opt
Dec 7, 2021
df545e5
add translate_binder
Dec 7, 2021
9c76b34
removed assert false
Dec 8, 2021
16b0dba
Merge branch 'master' into feat/default-option
Dec 14, 2021
65ad229
scope_let translation 2/6
Dec 15, 2021
0d1363b
wip
Dec 15, 2021
3a09b39
wip
Dec 16, 2021
63ff6cf
wip (compiling but can't compile catala program without internal errors)
Dec 16, 2021
c3268cc
more mistakes removed
Dec 16, 2021
84cd6dd
error on empty everywhere
Dec 17, 2021
2d26747
tentative beta reduction
Dec 17, 2021
1bfb891
printing dcalc and lcalc ast
Jan 25, 2022
33d9d03
advancing
Jan 28, 2022
fcf6fec
implementation of a few cases in the translation without exceptions
Jan 28, 2022
90a63eb
finished implementation of translation_expr + some documentation
Feb 1, 2022
0a612bf
translate_scope_let
Feb 2, 2022
717915b
more documentation
Feb 2, 2022
3c5bc4f
before removing the old file
Feb 2, 2022
2c4f9bf
removed the old file
Feb 2, 2022
67ccfb0
renamed the new file
Feb 2, 2022
d7c422d
clarify make_matchopt + lcalc's ast ocamlformat
Feb 2, 2022
1db649d
nicer internal error when Not_Found is raised inside the code generat…
Feb 2, 2022
6158a2e
nicer error messages when Not_Found error is raised inside the compil…
Feb 2, 2022
4290059
newline
Feb 2, 2022
ef7f25b
runtime correct type
Feb 3, 2022
85fc1be
printing ctx at each steps but no error found so far.
Feb 3, 2022
3e96db4
more printing to debug
Feb 3, 2022
156dd71
intermediate step
Feb 3, 2022
ebc2adc
removed comments
Feb 3, 2022
005646d
implementation of scoping let function
Feb 3, 2022
9e30133
more printing
Feb 3, 2022
b777d32
computing of free vars+ more debuging
Feb 4, 2022
88eedbc
ocamlformat
Feb 4, 2022
f8343d1
cleanup lcalc-ast.ml
Feb 4, 2022
6da5cc5
cleanup dcalc-ast.ml
Feb 4, 2022
154baef
runtime fix
Feb 4, 2022
08651d3
better error message in to_ocaml conversion
Feb 4, 2022
541d565
print uid too in Lcalc.Print
Feb 4, 2022
d9fbe4b
use external pp in compile_without_exceptions
Feb 4, 2022
02187b4
removed useless file
Feb 4, 2022
6ad948e
more cleanup in lcalc-ast
Feb 4, 2022
a06dfbf
Assets and formatting
denismerigoux Feb 4, 2022
97f8875
Merge branch 'master' into alain_default-option
denismerigoux Feb 4, 2022
b44e8e4
changed optimization so it actually work
Feb 4, 2022
424b68a
formatting
Feb 4, 2022
c97ab86
removed un-used code
Feb 4, 2022
730bd71
new invariant about assert in dcalc
Feb 4, 2022
0160567
forcing the invariant of the previous commit
Feb 7, 2022
16e09a1
type translation
Feb 7, 2022
ed2c192
Add monomorphisation of eoptions types
Feb 7, 2022
3a1ab17
fix uncorrect scope definition
Feb 7, 2022
29b734b
reorganisation of the file compile_without exceptions
Feb 9, 2022
bd0fe18
handling with special care SubScopeVarDefinition using the invariant …
Feb 9, 2022
72da935
chaging pretty printer for type to Dcalc.Print.format_typ
Feb 9, 2022
8834034
disable beta-reduction
Feb 11, 2022
cf28a58
cut --> hoist
Feb 11, 2022
77051ca
fmt
Feb 11, 2022
80fa311
documentation + finished translating cut to hoist + copyright inside …
Feb 12, 2022
9a718c6
Format comments
denismerigoux Feb 14, 2022
69a7465
Merge branch 'master' into alain_default-option
denismerigoux Feb 14, 2022
3322869
Correct assets
denismerigoux Feb 14, 2022
cab4e5c
Merge branch 'master' into alain_default-option
denismerigoux Feb 15, 2022
48f064c
Adapt translation to new i/o invariants, bug discovered
denismerigoux Feb 15, 2022
19bf2d9
dcalc review
Feb 18, 2022
7e1057c
review of lcalc
Feb 18, 2022
d512b27
fmt
Feb 18, 2022
137fb8c
util review
Feb 18, 2022
f54b3b3
review lcalc
Feb 18, 2022
4b1f235
util review (bis)
Feb 18, 2022
5c9996e
more comment
Feb 18, 2022
d7b9aa9
fixing if-then-else bug
Feb 18, 2022
6fe75f3
fv --> free_vars_set
Feb 21, 2022
f7b70b8
add typing information to make_none and make_some
Feb 21, 2022
4ee9b71
to_lcalc option type printing
Feb 21, 2022
756e7cb
Merge branch 'master' into alain_default-option
denismerigoux Feb 24, 2022
c65c38a
Correct flag for enabling optimization
denismerigoux Feb 24, 2022
ddacc94
Correct types for make_some and make_none
denismerigoux Feb 24, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .nix/no-web.patch
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ index 31d5289..0000000
- (language : Js.js_string Js.t) (trace : bool) =
- driver
- (Contents (Js.to_string contents))
- false false false "Interpret"
- false false false false "Interpret"
- (Some (Js.to_string language))
- None trace false false
- (Some (Js.to_string scope))
Expand Down
2 changes: 1 addition & 1 deletion compiler/catala_web_interpreter.ml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ let _ =
(language : Js.js_string Js.t) (trace : bool) =
driver
(Contents (Js.to_string contents))
false false false "Interpret"
false false false false "Interpret"
(Some (Js.to_string language))
None trace false false
(Some (Js.to_string scope))
Expand Down
30 changes: 26 additions & 4 deletions compiler/dcalc/ast.ml
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ type log_entry = VarDef of typ | BeginCall | EndCall | PosRecordIfTrueBool
type unop =
| Not
| Minus of op_kind
| Log of log_entry * (Utils.Uid.MarkedString.info list[@opaque])
| Log of log_entry * Utils.Uid.MarkedString.info list
| Length
| IntToRat
| GetDay
Expand All @@ -103,7 +103,7 @@ type unop =
type operator = Ternop of ternop | Binop of binop | Unop of unop

type expr =
| EVar of (expr Bindlib.var[@opaque]) Pos.marked
| EVar of expr Bindlib.var Pos.marked
| ETuple of expr Pos.marked list * struct_name option
| ETupleAccess of expr Pos.marked * int * struct_name option * typ Pos.marked list
| EInj of expr Pos.marked * int * enum_name * typ Pos.marked list
Expand Down Expand Up @@ -143,8 +143,8 @@ type scope_let = {

type scope_body = {
scope_body_lets : scope_let list;
scope_body_result : expr Pos.marked Bindlib.box;
scope_body_arg : expr Bindlib.var;
scope_body_result : expr Pos.marked Bindlib.box; (** {x1 = x1; x2 = x2; x3 = x3; ... } *)
scope_body_arg : expr Bindlib.var; (** x: input_struct *)
scope_body_input_struct : StructName.t;
scope_body_output_struct : StructName.t;
}
Expand All @@ -164,6 +164,28 @@ end

module VarMap = Map.Make (Var)

let union : unit VarMap.t -> unit VarMap.t -> unit VarMap.t = VarMap.union (fun _ _ _ -> Some ())

let rec free_vars_set (e : expr Pos.marked) : unit VarMap.t =
match Pos.unmark e with
| EVar (v, _) -> VarMap.singleton v ()
| ETuple (es, _) | EArray es -> es |> List.map free_vars_set |> List.fold_left union VarMap.empty
| ETupleAccess (e1, _, _, _) | EAssert e1 | ErrorOnEmpty e1 | EInj (e1, _, _, _) ->
free_vars_set e1
| EApp (e1, es) | EMatch (e1, es, _) ->
e1 :: es |> List.map free_vars_set |> List.fold_left union VarMap.empty
| EDefault (es, ejust, econs) ->
ejust :: econs :: es |> List.map free_vars_set |> List.fold_left union VarMap.empty
| EOp _ | ELit _ -> VarMap.empty
| EIfThenElse (e1, e2, e3) ->
[ e1; e2; e3 ] |> List.map free_vars_set |> List.fold_left union VarMap.empty
| EAbs ((binder, _), _) ->
let vs, body = Bindlib.unmbind binder in
Array.fold_right VarMap.remove vs (free_vars_set body)

let free_vars_list (e : expr Pos.marked) : Var.t list =
free_vars_set e |> VarMap.bindings |> List.map fst

type vars = expr Bindlib.mvar

let make_var ((x, pos) : Var.t Pos.marked) : expr Pos.marked Bindlib.box =
Expand Down
6 changes: 5 additions & 1 deletion compiler/dcalc/ast.mli
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ type expr =
(** The [MarkedString.info] is the former enum case name *)
| EArray of expr Pos.marked list
| ELit of lit
| EAbs of (expr, expr Pos.marked) Bindlib.mbinder Pos.marked * typ Pos.marked list
| EAbs of ((expr, expr Pos.marked) Bindlib.mbinder[@opaque]) Pos.marked * typ Pos.marked list
| EApp of expr Pos.marked * expr Pos.marked list
| EAssert of expr Pos.marked
| EOp of operator
Expand Down Expand Up @@ -183,6 +183,10 @@ end

module VarMap : Map.S with type key = Var.t

val free_vars_set : expr Pos.marked -> unit VarMap.t

val free_vars_list : expr Pos.marked -> Var.t list

type vars = expr Bindlib.mvar

val make_var : Var.t Pos.marked -> expr Pos.marked Bindlib.box
Expand Down
132 changes: 132 additions & 0 deletions compiler/dcalc/binded_representation.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
(* This file is part of the Catala compiler, a specification language for tax and social benefits
computation rules. Copyright (C) 2020-2022 Inria, contributor: Alain Delaët-Tixeuil
<[email protected]>

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 = Ast

type scope_lets =
| Result of D.expr Pos.marked
| ScopeLet of {
scope_let_kind : D.scope_let_kind;
scope_let_typ : D.typ Pos.marked;
scope_let_expr : D.expr Pos.marked;
scope_let_next : (D.expr, scope_lets) Bindlib.binder;
scope_let_pos : Pos.t;
}

type scope_body = {
scope_body_input_struct : D.StructName.t;
scope_body_output_struct : D.StructName.t;
scope_body_result : (D.expr, scope_lets) Bindlib.binder;
}

type scopes =
| Nil
| ScopeDef of {
scope_name : D.ScopeName.t;
scope_body : scope_body;
scope_next : (D.expr, scopes) Bindlib.binder;
}

let union : unit D.VarMap.t -> unit D.VarMap.t -> unit D.VarMap.t =
D.VarMap.union (fun _ _ _ -> Some ())

let rec free_vars_set_scope_lets (scope_lets : scope_lets) : unit D.VarMap.t =
match scope_lets with
| Result e -> D.free_vars_set e
| ScopeLet { scope_let_expr = e; scope_let_next = next; _ } ->
let v, body = Bindlib.unbind next in
union (D.free_vars_set e) (D.VarMap.remove v (free_vars_set_scope_lets body))

let free_vars_set_scope_body (scope_body : scope_body) : unit D.VarMap.t =
let { scope_body_result = binder; _ } = scope_body in
let v, body = Bindlib.unbind binder in
D.VarMap.remove v (free_vars_set_scope_lets body)

let rec free_vars_set_scopes (scopes : scopes) : unit D.VarMap.t =
match scopes with
| Nil -> D.VarMap.empty
| ScopeDef { scope_body = body; scope_next = next; _ } ->
let v, next = Bindlib.unbind next in

union (D.VarMap.remove v (free_vars_set_scopes next)) (free_vars_set_scope_body body)

let free_vars_list_scope_lets (scope_lets : scope_lets) : D.Var.t list =
free_vars_set_scope_lets scope_lets |> D.VarMap.bindings |> List.map fst

let free_vars_list_scope_body (scope_body : scope_body) : D.Var.t list =
free_vars_set_scope_body scope_body |> D.VarMap.bindings |> List.map fst

let free_vars_list_scopes (scopes : scopes) : D.Var.t list =
free_vars_set_scopes scopes |> D.VarMap.bindings |> List.map fst

(** Actual transformation for scopes. *)
let bind_scope_lets (acc : scope_lets Bindlib.box) (scope_let : D.scope_let) :
scope_lets Bindlib.box =
let pos = snd scope_let.D.scope_let_var in

(* Cli.debug_print @@ Format.asprintf "binding let %a. Variable occurs = %b" Print.format_var (fst
scope_let.D.scope_let_var) (Bindlib.occur (fst scope_let.D.scope_let_var) acc); *)
let binder = Bindlib.bind_var (fst scope_let.D.scope_let_var) acc in
Bindlib.box_apply2
(fun expr binder ->
(* Cli.debug_print @@ Format.asprintf "free variables in expression: %a" (Format.pp_print_list
Print.format_var) (D.free_vars_list expr); *)
ScopeLet
{
scope_let_kind = scope_let.D.scope_let_kind;
scope_let_typ = scope_let.D.scope_let_typ;
scope_let_expr = expr;
scope_let_next = binder;
scope_let_pos = pos;
})
scope_let.D.scope_let_expr binder

let bind_scope_body (body : D.scope_body) : scope_body Bindlib.box =
(* it is a fold_right and not a fold_left. *)
let body_result =
ListLabels.fold_right body.D.scope_body_lets
~init:(Bindlib.box_apply (fun e -> Result e) body.D.scope_body_result)
~f:(Fun.flip bind_scope_lets)
in

(* Cli.debug_print @@ Format.asprintf "binding arg %a" Print.format_var body.D.scope_body_arg; *)
let scope_body_result = Bindlib.bind_var body.D.scope_body_arg body_result in

(* Cli.debug_print @@ Format.asprintf "isfinal term is closed: %b" (Bindlib.is_closed
scope_body_result); *)
Bindlib.box_apply
(fun scope_body_result ->
(* Cli.debug_print @@ Format.asprintf "rank of the final term: %i" (Bindlib.binder_rank
scope_body_result); *)
{
scope_body_output_struct = body.D.scope_body_output_struct;
scope_body_input_struct = body.D.scope_body_input_struct;
scope_body_result;
})
scope_body_result

let bind_scope
((scope_name, scope_var, scope_body) : D.ScopeName.t * D.expr Bindlib.var * D.scope_body)
(acc : scopes Bindlib.box) : scopes Bindlib.box =
Bindlib.box_apply2
(fun scope_body scope_next -> ScopeDef { scope_name; scope_body; scope_next })
(bind_scope_body scope_body) (Bindlib.bind_var scope_var acc)

let bind_scopes (scopes : (D.ScopeName.t * D.expr Bindlib.var * D.scope_body) list) :
scopes Bindlib.box =
let result = ListLabels.fold_right scopes ~init:(Bindlib.box Nil) ~f:bind_scope in
(* Cli.debug_print @@ Format.asprintf "free variable in the program : [%a]" (Format.pp_print_list
Print.format_var) (free_vars_list_scopes (Bindlib.unbox result)); *)
result
63 changes: 63 additions & 0 deletions compiler/dcalc/binded_representation.mli
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
(* This file is part of the Catala compiler, a specification language for tax and social benefits
computation rules. Copyright (C) 2020-2022 Inria, contributor: Alain Delaët-Tixeuil
<[email protected]>

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. *)

module D = Ast

(** Alternative representation of the Dcalc Ast. It is currently used in the transformation without
adelaett marked this conversation as resolved.
Show resolved Hide resolved
exceptions. We make heavy use of bindlib, binding each scope-let-variable and each scope
explicitly. *)

(** In [Ast], [Ast.scope_lets] is defined as a list of kind, var, and boxed expression. This
representation binds using bindlib the tail of the list with the variable defined in the let. *)
type scope_lets =
| Result of D.expr Utils.Pos.marked
| ScopeLet of {
scope_let_kind : D.scope_let_kind;
scope_let_typ : D.typ Utils.Pos.marked;
scope_let_expr : D.expr Utils.Pos.marked;
scope_let_next : (D.expr, scope_lets) Bindlib.binder;
scope_let_pos : Utils.Pos.t;
}

type scope_body = {
scope_body_input_struct : D.StructName.t;
scope_body_output_struct : D.StructName.t;
scope_body_result : (D.expr, scope_lets) Bindlib.binder;
}
(** As a consequence, the scope_body contains only a result and input/output signature, as the other
elements are stored inside the scope_let. The binder present is the argument of type
[scope_body_input_struct]. *)

(** Finally, we do the same transformation for the whole program for the kinded lets. This permit us
to use bindlib variables for scopes names. *)
type scopes =
| Nil
| ScopeDef of {
scope_name : D.ScopeName.t;
scope_body : scope_body;
scope_next : (D.expr, scopes) Bindlib.binder;
}

val free_vars_list_scope_lets : scope_lets -> D.Var.t list
(** List of variables not binded inside a scope_lets *)

val free_vars_list_scope_body : scope_body -> D.Var.t list
(** List of variables not binded inside a scope_body. *)

val free_vars_list_scopes : scopes -> D.Var.t list
(** List of variables not binded inside scopes*)

val bind_scopes : (D.ScopeName.t * D.expr Bindlib.var * D.scope_body) list -> scopes Bindlib.box
(** Transform a list of scopes into our representation of scopes. It requires that scopes are
topologically-well-ordered, and ensure there is no free variables in the returned [scopes] *)
6 changes: 4 additions & 2 deletions compiler/dcalc/optimizations.ml
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,11 @@ let rec partial_evaluation (ctx : partial_evaluation_ctx) (e : expr Pos.marked)
((ELit (LBool false) | EApp ((EOp (Unop (Log _)), _), [ (ELit (LBool false), _) ])), _),
_ ) ->
(ELit LEmptyError, pos)
| [], just, cons ->
| [], just, cons when not !Cli.avoid_exceptions_flag ->
(* without exceptions, a default is just an [if then else] raising an error in the
else case *)
else case. This exception is only valid in the context of
compilation_with_exceptions, so we desactivate with a global flag to know if we
will be compiling using exceptions or the option monad. *)
(EIfThenElse (just, cons, (ELit LEmptyError, pos)), pos)
| exceptions, just, cons -> (EDefault (exceptions, just, cons), pos))
(List.map rec_helper exceptions |> Bindlib.box_list)
Expand Down
13 changes: 9 additions & 4 deletions compiler/driver.ml
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,17 @@ let extensions = [ (".catala_fr", "fr"); (".catala_en", "en"); (".catala_pl", "p
(** Entry function for the executable. Returns a negative number in case of error. Usage:
[driver source_file debug dcalc unstyled wrap_weaved_output backend language max_prec_digits trace optimize scope_to_execute output_file]*)
let driver (source_file : Pos.input_file) (debug : bool) (unstyled : bool)
(wrap_weaved_output : bool) (backend : string) (language : string option)
(max_prec_digits : int option) (trace : bool) (disable_counterexamples : bool) (optimize : bool)
(ex_scope : string option) (output_file : string option) : int =
(wrap_weaved_output : bool) (avoid_exceptions : bool) (backend : string)
(language : string option) (max_prec_digits : int option) (trace : bool)
(disable_counterexamples : bool) (optimize : bool) (ex_scope : string option)
(output_file : string option) : int =
try
Cli.debug_flag := debug;
Cli.style_flag := not unstyled;
Cli.trace_flag := trace;
Cli.optimize_flag := optimize;
Cli.disable_counterexamples := disable_counterexamples;
Cli.avoid_exceptions_flag := avoid_exceptions;
Cli.debug_print "Reading files...";
let filename = ref "" in
(match source_file with FileName f -> filename := f | Contents c -> Cli.contents := c);
Expand Down Expand Up @@ -255,7 +257,10 @@ let driver (source_file : Pos.input_file) (debug : bool) (unstyled : bool)
0
| Cli.OCaml | Cli.Python | Cli.Lcalc | Cli.Scalc ->
Cli.debug_print "Compiling program into lambda calculus...";
let prgm = Lcalc.Compile_with_exceptions.translate_program prgm in
let prgm =
if avoid_exceptions then Lcalc.Compile_without_exceptions.translate_program prgm
else Lcalc.Compile_with_exceptions.translate_program prgm
in
let prgm =
if optimize then begin
Cli.debug_print "Optimizing lambda calculus...";
Expand Down
Loading