open Base
module AstVarMap = Ast.Variable.Map
module Rules_Make = Rules.Make
module rec Rules : RULES = Rules_Make(Expression)
and Expression: EXPRESSION = struct
transform ?v exp map kcontext returns a CPS expression
obtained from the AST expression exp. map contains a map
from AST variables to CPS variables (several AST variables can
correspond to the same CPS variables). The CPS expression is
"returned" as a CPS (normal) variable var, such that if the CPS
expression and the AST expression were both evaluated, var
would contain the result of the evaluation of exp.CPS transformation is written itself in CPS style, so it takes a
continuation argument kcontext to which var is returned.
kcontext represents the context that will use the result of the
transformation.
When a v argument is given, then this v is the var bound to
the result of the CPS expression and is returned. This is used
when compiling recursive occurrences. 
  
let rec transform ?v exp map kcontext =
    
let (exp_,_) = exp inv for now. We could
also handle data structures with a pointer indirection, such as
injections. 
Cpsbuild module: often it suffices to pass kcontext
as the continuation argument of the Cpsbuild functions. 
    
∣ Ast.Expression.Variable(var) → 
      
let v = try AstVarMap.find var map
        
(∗  Should not happen: any unbound variable error should have
been already caught by the type checker.  ∗)
        
with Not_found → Log.Cps_transformation.raise_compiler_error
          
"Unbound variable %s" (Ast.Variable.to_string var) in
      
kcontext v    
∣ Ast.Expression.Constant(c) → Build.let_constant c kcontext
    
∣ Ast.Expression.External(name, _) → Build.let_external name kcontext
    
∣ Ast.Expression.Injection(j,n,x) →
      
transform x map (fun injectedv →
        
Build.let_inj j n injectedv kcontext)
    
∣ Ast.Expression.Cast(_,x) → transform x map kcontext
    
∣ Ast.Expression.Tuple(l) →
      
let f accu exp k = transform exp map (fun expv → k (expv::accu)) in
      
List.foldk f [ ] l (fun vs →
        
Build.let_tuple (List.rev vs) kcontext)
    
∣ Ast.Expression.Apply(((Ast.Expression.Constant c),_),
                            
[(Ast.Expression.Tuple([a;b]),_)]) →
      
transform a map (fun av →
        
transform b map (fun bv →
          
let buildf = match c with
            
∣ Constant.Integer_binary_operation(op) →
              
Build.let_integer_binary_operation op
            
∣ Constant.Integer_binary_predicate(pred) →
              
Build.let_integer_binary_predicate pred in
          
buildf av bv kcontext))