Module Qcert.Translation.Lang.NNRCtoJava


Require Import List.
Require Import String.
Require Import BinInt.
Require Import Ascii.
Require Import Peano_dec.
Require Import EquivDec.
Require Import Utils.
Require Import DataRuntime.
Require Import JavaRuntime.
Require Import NNRCRuntime.
Require Import ForeignToJava.

Import ListNotations.
Local Open Scope string_scope.

Section NNRCtoJava.
  Section sanitizer.
    Definition unshadow_java {fruntime:foreign_runtime} (avoid:list var) (e:nnrc) : nnrc
      := unshadow javaSafeSeparator javaIdentifierSanitize (avoid++javaAvoidList) e.

    Definition javaSanitizeNNRC {fruntime:foreign_runtime} (e:nnrc) : nnrc
      := unshadow_java nil e.

  End sanitizer.

  Context {fruntime:foreign_runtime}.

  Section DataJava.
    Context {ftojavajson:foreign_to_java}.

    Definition mk_java_json_brands (quotel:string) (b:brands) : java_json
      := mk_java_json_array (map (mk_java_json_string quotel) b).

    Fixpoint mk_java_json_data (quotel:string) (d : data) : java_json :=
      match d with
      | dunit => java_json_NULL
      | dnat n => mk_java_json_nat quotel n
      | dfloat n => mk_java_json_number n
      | dbool b => mk_java_json_bool b
      | dstring s => mk_java_json_string quotel s
      | dcoll ls => mk_java_json_array (map (mk_java_json_data quotel) ls)
      | drec ls => mk_java_json_object
                     quotel
                     (map (fun kv =>
                             let '(k,v) := kv in
                             (k, (mk_java_json_data quotel v))) ls)
      | dleft d => mk_java_json_object quotel
                                       [("$left", (mk_java_json_data quotel d))]
                                       
      | dright d => mk_java_json_object quotel
                                        [("$right", (mk_java_json_data quotel d))]
                                        
      | dbrand b d =>
        mk_java_json_object quotel
                            [("$data", mk_java_json_data quotel d)
                             ; ("$type", mk_java_json_brands quotel b)]
      | dforeign fd => foreign_to_java_data quotel fd
      end.

  End DataJava.

  Section test.
    Import ListNotations.
    
    Definition testd
      := drec (rec_sort [
                   ("hi", dcoll [dnat 3; dnat 4])
                   ; ("there", dbool false)
                   ; ("is", dstring "hi")
                   ; ("b", dbrand ["C1"; "I1"; "C2"]
                                  (dcoll [dbool true; dbool false]))]).
    Context {ftojavajson:foreign_to_java}.
    
    
  End test.

  Section NNRCJava.
    Context {ftojavajson:foreign_to_java}.
    Import ListNotations.

    Definition uarithToJavaMethod (u:nat_arith_unary_op) :=
      match u with
      | NatAbs => "abs"
      | NatLog2 => "log2"
      | NatSqrt =>"sqrt"
      end.

    Definition float_uarithToJavaMethod (fu:float_arith_unary_op) :=
      match fu with
      | FloatNeg => "float_neg"
      | FloatSqrt => "float_sqrt"
      | FloatExp => "float_exp"
      | FloatLog => "float_log"
      | FloatLog10 => "float_log10"
      | FloatCeil => "float_ceil"
      | FloatFloor => "float_floor"
      | FloatAbs => "float_abs"
      end.

    Definition nat_barithToJavaMethod (b:nat_arith_binary_op) :=
      match b with
      | NatPlus => "plus"
      | NatMinus => "minus "
      | NatMult => "mult"
      | NatDiv => "divide"
      | NatRem => "rem"
      | NatMin => "min"
      | NatMax => "max"
      end.

    Definition float_barithToJavaMethod (fb:float_arith_binary_op)
      := match fb with
         | FloatPlus => "float_plus"
         | FloatMinus => "float_minus"
         | FloatMult => "float_mult"
         | FloatDiv => "float_divide"
         | FloatPow => "float_pow"
         | FloatMin => "float_min"
         | FloatMax => "float_max"
         end.

    Definition float_bcompareToJavaMethod (fb:float_compare_binary_op)
      := match fb with
         | FloatLt => "float_lt"
         | FloatLe => "float_le"
         | FloatGt => "float_gt"
         | FloatGe => "float_ge"
         end.

    Definition like_clause_to_java (lc:like_clause)
      := match lc with
         | like_literal literal => "new UnaryOperators.LiteralLikeClause(" ++ (mk_java_string literal) ++ ")"
         | like_any_char => "new UnaryOperators.AnyCharLikeClause()"
         | like_any_string => "new UnaryOperators.AnyStringLikeClause()"
         end.
    
    Fixpoint nnrcToJava
             (n : nnrc)
             (t : nat)
             (i : nat)
             (eol : string)
             (quotel : string)
             (ivs : list (string * string))
      : string
        * java_json
        * nat
      := match n with
         | NNRCGetConstant v =>
           ("", mk_java_json ("v" ++ v), t)
         | NNRCVar v =>
           match assoc_lookupr equiv_dec ivs v with
           | Some v_string => ("", mk_java_json v_string, t)
           | None => ("", mk_java_json ("v" ++ v), t)
           end
         | NNRCConst d => ("", (mk_java_json_data quotel d), t)
         | NNRCUnop op n1 =>
           let '(s1, e1, t0) := nnrcToJava n1 t i eol quotel ivs in
           let e0 := match op with
                     | OpIdentity => e1
                     | OpNeg => mk_java_unary_op0 "neg" e1
                     | OpRec s => mk_java_unary_op1 "rec" (mk_java_string s) e1
                     | OpDot s => mk_java_unary_op1 "dot" (mk_java_string s) e1
                     | OpRecRemove s => mk_java_unary_op1 "remove" (mk_java_string s) e1
                     | OpRecProject sl => mk_java_unary_op1 "project" (mk_java_string_collection sl) e1
                     | OpBag => mk_java_unary_op0 "coll" e1
                     | OpSingleton => mk_java_unary_op0 "singleton" e1
                     | OpFlatten => mk_java_unary_op0 "flatten" e1
                     | OpDistinct => mk_java_unary_op0 "distinct" e1
                     | OpOrderBy sl =>
                       mk_java_unary_op1 "sort" (mk_java_sort_criterias quotel sl) e1
                     | OpCount => mk_java_unary_op0 "count" e1
                     | OpToString => mk_java_unary_op0 "tostring" e1
                     | OpToText => mk_java_unary_op0 "totext" e1
                     | OpLength => mk_java_unary_op0 "stringlength" e1
                     | OpSubstring start olen =>
                       match olen with
                       | Some len => mk_java_unary_opn "substring" (map toString [start; len]) e1
                       | None => mk_java_unary_op1 "substring" (toString start) e1
                       end
                     | OpLike pat =>
                       let lc := make_like_clause pat None in
                       mk_java_unary_op1 "string_like" ("new UnaryOperators.LikeClause[]{"
                                         ++ (map_concat "," like_clause_to_java lc) ++ "}") e1
                     | OpLeft => mk_java_unary_op0 "left" e1
                     | OpRight => mk_java_unary_op0 "right" e1
                     | OpBrand b =>mk_java_unary_op1 "brand" (mk_java_string_collection b) e1
                     | OpUnbrand => mk_java_unary_op0 "unbrand" e1
                     | OpCast b => mk_java_unary_opn "cast" ["inheritance"; (mk_java_string_collection b)] e1
                     | OpNatUnary u => mk_java_unary_op0 (uarithToJavaMethod u) e1
                     | OpNatSum => mk_java_unary_op0 "sum" e1
                     | OpNatMin => mk_java_unary_op0 "list_min" e1
                     | OpNatMax => mk_java_unary_op0 "list_max" e1
                     | OpNatMean => mk_java_unary_op0 "list_mean" e1
                     | OpFloatOfNat => mk_java_unary_op0 "float_of_int" e1
                     | OpFloatUnary u => mk_java_unary_op0 (float_uarithToJavaMethod u) e1
                     | OpFloatTruncate => mk_java_unary_op0 "float_truncate" e1
                     | OpFloatSum => mk_java_unary_op0 "float_sum" e1
                     | OpFloatBagMin => mk_java_unary_op0 "float_list_min" e1
                     | OpFloatBagMax => mk_java_unary_op0 "float_list_max" e1
                     | OpFloatMean => mk_java_unary_op0 "float_list_mean" e1
                     | OpForeignUnary fu
                       => foreign_to_java_unary_op i eol quotel fu e1
                     end in
           (s1, e0, t0)
         | NNRCBinop op n1 n2 =>
           let '(s1, e1, t2) := nnrcToJava n1 t i eol quotel ivs in
           let '(s2, e2, t0) := nnrcToJava n2 t2 i eol quotel ivs in
           let e0 := match op with
                     | OpEqual => mk_java_binary_op0 "equals" e1 e2
                     | OpRecConcat => mk_java_binary_op0 "concat" e1 e2
                     | OpRecMerge => mk_java_binary_op0 "mergeConcat" e1 e2
                     | OpAnd => mk_java_binary_op0 "and" e1 e2
                     | OpOr => mk_java_binary_op0 "or" e1 e2
                     | OpLt => mk_java_binary_op0 "lt" e1 e2
                     | OpLe => mk_java_binary_op0 "le" e1 e2
                     | OpBagUnion => mk_java_binary_op0 "union" e1 e2
                     | OpBagDiff => mk_java_binary_op0 "bag_minus" e1 e2
                     | OpBagMin => mk_java_binary_op0 "bag_min" e1 e2
                     | OpBagMax => mk_java_binary_op0 "bag_max" e1 e2
                     | OpBagNth => mk_java_binary_op0 "bag_nth" e1 e2
                     | OpContains => mk_java_binary_op0 "contains" e1 e2
                     | OpStringConcat => mk_java_binary_op0 "stringConcat" e1 e2
                     | OpStringJoin => mk_java_binary_op0 "stringJoin" e1 e2
                     | OpNatBinary b => mk_java_binary_op0 (nat_barithToJavaMethod b) e1 e2
                     | OpFloatBinary b => mk_java_binary_op0 (float_barithToJavaMethod b) e1 e2
                     | OpFloatCompare b => mk_java_binary_op0 (float_bcompareToJavaMethod b) e1 e2
                     | OpForeignBinary fb
                       => foreign_to_java_binary_op i eol quotel fb e1 e2
                     end in
           (s1 ++ s2, e0, t0)
         | NNRCLet v bind body =>
           let '(s1, e1, t2) := nnrcToJava bind t i eol quotel ivs in
           let '(s2, e2, t0) := nnrcToJava body t2 i eol quotel ivs in
           let v0 := "v" ++ v in
           let ret := "vletvar$" ++ v ++ "$" ++ (nat_to_string10 t0) in
           (s1
              ++ (indent i) ++ "final JsonElement " ++ ret ++ ";" ++ eol
              ++ (indent i) ++ "{ // new scope introduced for a let statement" ++ eol
              ++ (indent (i+1)) ++ "final JsonElement " ++ v0 ++ " = " ++ (from_java_json e1) ++ ";" ++ eol
              ++ s2
              ++ (indent (i+1)) ++ ret ++ " = " ++ (from_java_json e2) ++ ";" ++ eol
              ++ (indent i) ++ "}" ++ eol,
            mk_java_json ret, t0+1)
         | NNRCFor v iter body =>
           let '(s1, e1, t2) := nnrcToJava iter t i eol quotel ivs in
           let '(s2, e2, t0) := nnrcToJava body t2 (i+1) eol quotel ivs in
           let elm := "v" ++ v in
           let src := "src" ++ (nat_to_string10 t0) in
           let idx := "i" ++ (nat_to_string10 t0) in
           let dst := "dst" ++ (nat_to_string10 t0) in
           (s1 ++ (indent i) ++ "final JsonArray " ++ src ++ " = (JsonArray) " ++ (from_java_json e1) ++ ";" ++ eol
               ++ (indent i) ++ "final JsonArray " ++ dst ++ " = new JsonArray();" ++ eol
               ++ (indent i) ++ "for(int " ++ idx ++ " = 0; " ++ idx ++ " < " ++ src ++ ".size(); " ++ idx ++ "++) {" ++ eol
               ++ (indent (i+1)) ++ "final JsonElement " ++ elm ++ " = " ++ src ++ ".get(" ++ idx ++ ");" ++ eol
               ++ s2
               ++ (indent (i+1)) ++ dst ++ ".add(" ++ (from_java_json e2) ++ ");" ++ eol
               ++ (indent i) ++ "}" ++ eol,
            (mk_java_json dst), t0 + 1)
         | NNRCIf c n1 n2 =>
           let '(s1, e1, t2) := nnrcToJava c t i eol quotel ivs in
           let '(s2, e2, t3) := nnrcToJava n1 t2 (i+1) eol quotel ivs in
           let '(s3, e3, t0) := nnrcToJava n2 t3 (i+1) eol quotel ivs in
           let v0 := "t" ++ (nat_to_string10 t0) in
           (s1 ++ (indent i) ++ "final JsonElement " ++ v0 ++ ";" ++ eol
               ++ (indent i) ++ "if (RuntimeUtils.asBoolean(" ++ (from_java_json e1) ++ ")) {" ++ eol
               ++ s2
               ++ (indent (i+1)) ++ v0 ++ " = " ++ (from_java_json e2) ++ ";" ++ eol
               ++ (indent i) ++ "} else {" ++ eol
               ++ s3
               ++ (indent (i+1)) ++ v0 ++ " = " ++ (from_java_json e3) ++ ";" ++ eol
               ++ (indent i) ++ "}" ++ eol,
            (mk_java_json v0), t0 + 1)
         | NNRCEither nd xl nl xr nr =>
           let '(s1, e1, t2) := nnrcToJava nd t i eol quotel ivs in
           let '(s2, e2, t1) := nnrcToJava nl t2 (i+1) eol quotel ivs in
           let '(s3, e3, t0) := nnrcToJava nr t1 (i+1) eol quotel ivs in
           let vl := "v" ++ xl in
           let vr := "v" ++ xr in
           let res := "res" ++ (nat_to_string10 t0) in
           (s1 ++ (indent i) ++ "final JsonElement " ++ res ++ ";" ++ eol
               ++ (indent i) ++ "if (RuntimeUtils.either(" ++ (from_java_json e1) ++")) {" ++ eol
               ++ (indent (i+1)) ++ "final JsonElement " ++ vl ++ eol
               ++ (indent (i+1)) ++ " = RuntimeUtils.getLeft(" ++ (from_java_json e1) ++ ");" ++ eol
               ++ s2
               ++ (indent (i+1)) ++ res ++ " = " ++ (from_java_json e2) ++ ";" ++ eol
               ++ (indent i) ++ "} else {" ++ eol
               ++ (indent (i+1)) ++ "final JsonElement " ++ vr ++ eol
               ++ (indent (i+1)) ++ " = RuntimeUtils.getRight(" ++ (from_java_json e1) ++ ");" ++ eol
               ++ s3
               ++ (indent (i+1)) ++ res ++ " = " ++ (from_java_json e3) ++ ";" ++ eol
               ++ (indent i) ++ "}" ++ eol,
            mk_java_json res, t0 + 1)
         | NNRCGroupBy g sl n1 =>
           let '(s1, e1, t0) := nnrcToJava n1 t i eol quotel ivs in
           let e0 := mk_java_unary_opn "groupby" [(mk_java_string g);(mk_java_string_collection sl)] e1 in
           (s1, e0, t0)
       end.

    Definition nnrcToJavaunshadow (n : nnrc) (t : nat) (i : nat) (eol : string) (quotel : string) (avoid: list var) (ivs : list (string * string)) :=
      let n := unshadow_java avoid n in
      nnrcToJava n t i eol quotel ivs.

    Definition makeJavaParams (ivs: list(string*string)) :=
      map_concat ", " (fun elem => "JsonElement " ++ snd elem) ivs.

    Definition closeFreeVars (input:string) (e:nnrc) (ivs:list(string*string)) : nnrc :=
      let all_free_vars := nnrc_global_vars e in
      let wrap_one_free_var (e':nnrc) (fv:string) : nnrc :=
          if (assoc_lookupr equiv_dec ivs fv)
          then e'
          else
            (NNRCLet fv (NNRCUnop (OpDot fv) (NNRCVar input)) e')
      in
      fold_left wrap_one_free_var all_free_vars e.
    
    Definition nnrcToJavaFun (i:nat) (input_v:string) (e:nnrc) (eol:string) (quotel:string) (ivs : list (string * string)) (fname:string) :=
      let e' := closeFreeVars input_v e ivs in
      let '(j0, v0, t0) := nnrcToJavaunshadow e' 1 (i + 1) eol quotel ("constants"::"inheritance"::(List.map fst ivs)) ivs in
      (indent i) ++ "public JsonElement " ++ fname ++ "(Inheritance inheritance, " ++ (makeJavaParams ivs) ++ ") {" ++ eol
                 ++ j0
                 ++ (indent i) ++ " return " ++ (from_java_json v0) ++ ";" ++ eol
                 ++ (indent i) ++ "}" ++ eol.

    Definition nnrcToJavaClass (class_name:string) (package_name:string) (imports:string) (input_v:string) (e:nnrc) (eol:string) (quotel:string) (ivs : list (string * string)) (fname:string) :=
      let f := nnrcToJavaFun 1 input_v e eol quotel ivs fname in
      (if(package_name == "")
      then ""
      else "package " ++ package_name ++ ";" ++ eol ++ eol)
        ++ "import com.google.gson.*;" ++ eol
        ++ (if(imports == "")
            then ""
            else "import " ++ imports ++ ";" ++ eol)
        ++ (if(package_name == "org.qcert.runtime")
            then ""
            else "import org.qcert.runtime.*;" ++ eol)
      ++ eol
      ++ "public class " ++ class_name ++ " implements JavaQuery { " ++ eol
      ++ f
      ++ "}" ++ eol
    .

    Definition nnrc_to_java_top (class_name:string) (imports:string) (e:nnrc) : java :=
      let input_f := "query" in
      let input_v := "constants" in
      nnrcToJavaClass class_name "" imports input_v e eol_newline quotel_double ((input_v, input_v)::nil) input_f.

  End NNRCJava.

End NNRCtoJava.