Module Qcert.EJson.Operators.EJsonRuntimeOperators


Imp with the Json data model

Require Import String.
Require Import List.
Require Import ZArith.
Require Import Utils.
Require Import BrandRelation.
Require Import ForeignEJson.
Require Import EJson.
Require Import EJsonGroupBy.
Require Import EJsonSortBy.
Require Import ForeignEJsonRuntime.

Section EJsonRuntimeOperators.
  Local Open Scope string.

  Context {foreign_ejson_model:Set}.
  Context {fejson:foreign_ejson foreign_ejson_model}.
  Context {foreign_ejson_runtime_op : Set}.

  Section Syntax.
    Inductive ejson_runtime_op :=
    | EJsonRuntimeEqual : ejson_runtime_op
    | EJsonRuntimeCompare : ejson_runtime_op
    | EJsonRuntimeToString : ejson_runtime_op
    | EJsonRuntimeToText : ejson_runtime_op
    | EJsonRuntimeRecConcat : ejson_runtime_op
    | EJsonRuntimeRecMerge : ejson_runtime_op
    | EJsonRuntimeRecRemove: ejson_runtime_op
    | EJsonRuntimeRecProject: ejson_runtime_op
    | EJsonRuntimeRecDot : ejson_runtime_op
    | EJsonRuntimeArray : ejson_runtime_op
    | EJsonRuntimeArrayLength : ejson_runtime_op
    | EJsonRuntimeArrayPush : ejson_runtime_op
    | EJsonRuntimeArrayAccess : ejson_runtime_op
    | EJsonRuntimeEither : ejson_runtime_op
    | EJsonRuntimeToLeft: ejson_runtime_op
    | EJsonRuntimeToRight: ejson_runtime_op
    | EJsonRuntimeUnbrand : ejson_runtime_op
    | EJsonRuntimeCast : ejson_runtime_op
    | EJsonRuntimeDistinct : ejson_runtime_op
    | EJsonRuntimeSingleton : ejson_runtime_op
    | EJsonRuntimeFlatten : ejson_runtime_op
    | EJsonRuntimeUnion : ejson_runtime_op
    | EJsonRuntimeMinus : ejson_runtime_op
    | EJsonRuntimeMin : ejson_runtime_op
    | EJsonRuntimeMax : ejson_runtime_op
    | EJsonRuntimeNth : ejson_runtime_op
    | EJsonRuntimeCount : ejson_runtime_op
    | EJsonRuntimeContains : ejson_runtime_op
    | EJsonRuntimeSort : ejson_runtime_op
    | EJsonRuntimeGroupBy : ejson_runtime_op
    | EJsonRuntimeLength : ejson_runtime_op
    | EJsonRuntimeSubstring : ejson_runtime_op
    | EJsonRuntimeSubstringEnd : ejson_runtime_op
    | EJsonRuntimeStringJoin : ejson_runtime_op
    | EJsonRuntimeLike : ejson_runtime_op
    | EJsonRuntimeNatLt : ejson_runtime_op
    | EJsonRuntimeNatLe : ejson_runtime_op
    | EJsonRuntimeNatPlus : ejson_runtime_op
    | EJsonRuntimeNatMinus : ejson_runtime_op
    | EJsonRuntimeNatMult : ejson_runtime_op
    | EJsonRuntimeNatDiv : ejson_runtime_op
    | EJsonRuntimeNatRem : ejson_runtime_op
    | EJsonRuntimeNatAbs : ejson_runtime_op
    | EJsonRuntimeNatLog2 : ejson_runtime_op
    | EJsonRuntimeNatSqrt : ejson_runtime_op
    | EJsonRuntimeNatMinPair : ejson_runtime_op
    | EJsonRuntimeNatMaxPair : ejson_runtime_op
    | EJsonRuntimeNatSum : ejson_runtime_op
    | EJsonRuntimeNatMin : ejson_runtime_op
    | EJsonRuntimeNatMax : ejson_runtime_op
    | EJsonRuntimeNatArithMean : ejson_runtime_op
    | EJsonRuntimeFloatOfNat : ejson_runtime_op
    | EJsonRuntimeFloatSum : ejson_runtime_op
    | EJsonRuntimeFloatArithMean : ejson_runtime_op
    | EJsonRuntimeFloatMin : ejson_runtime_op
    | EJsonRuntimeFloatMax : ejson_runtime_op
    | EJsonRuntimeNatOfFloat : ejson_runtime_op
    | EJsonRuntimeForeign (fop:foreign_ejson_runtime_op) : ejson_runtime_op
    .

  End Syntax.

  Context {fejruntime:foreign_ejson_runtime foreign_ejson_runtime_op}.

  Section Util.
    Local Open Scope string.

    Definition string_of_ejson_runtime_op (op: ejson_runtime_op) :=
      match op with
      | EJsonRuntimeEqual => "equal"
      | EJsonRuntimeCompare => "compare"
      | EJsonRuntimeToString => "toString"
      | EJsonRuntimeToText => "toText"
      | EJsonRuntimeRecConcat => "recConcat"
      | EJsonRuntimeRecMerge => "recMerge"
      | EJsonRuntimeRecRemove=> "recRemove"
      | EJsonRuntimeRecProject=> "recProject"
      | EJsonRuntimeRecDot => "recDot"
      | EJsonRuntimeArray => "array"
      | EJsonRuntimeArrayLength => "arrayLength"
      | EJsonRuntimeArrayPush => "arrayPush"
      | EJsonRuntimeArrayAccess => "arrayAccess"
      | EJsonRuntimeEither => "either"
      | EJsonRuntimeToLeft=> "getLeft"
      | EJsonRuntimeToRight=> "getRight"
      | EJsonRuntimeUnbrand => "unbrand"
      | EJsonRuntimeCast => "cast"
      | EJsonRuntimeDistinct => "distinct"
      | EJsonRuntimeSingleton => "singleton"
      | EJsonRuntimeFlatten => "flatten"
      | EJsonRuntimeUnion => "union"
      | EJsonRuntimeMinus => "minus"
      | EJsonRuntimeMin => "min"
      | EJsonRuntimeMax => "max"
      | EJsonRuntimeNth => "nth"
      | EJsonRuntimeCount => "count"
      | EJsonRuntimeContains => "contains"
      | EJsonRuntimeSort => "sort"
      | EJsonRuntimeGroupBy => "groupBy"
      | EJsonRuntimeLength => "length"
      | EJsonRuntimeSubstring => "substring"
      | EJsonRuntimeSubstringEnd => "substringEnd"
      | EJsonRuntimeStringJoin => "stringJoin"
      | EJsonRuntimeLike => "like"
      | EJsonRuntimeNatLt => "natLt"
      | EJsonRuntimeNatLe => "natLe"
      | EJsonRuntimeNatPlus => "natPlus"
      | EJsonRuntimeNatMinus => "natMinus"
      | EJsonRuntimeNatMult => "natMult"
      | EJsonRuntimeNatDiv => "natDiv"
      | EJsonRuntimeNatRem => "natRem"
      | EJsonRuntimeNatAbs => "natAbs"
      | EJsonRuntimeNatLog2 => "natLog2"
      | EJsonRuntimeNatSqrt => "natSqrt"
      | EJsonRuntimeNatMinPair => "natMinPair"
      | EJsonRuntimeNatMaxPair => "natMaxPair"
      | EJsonRuntimeNatMin => "natMin"
      | EJsonRuntimeNatMax => "natMax"
      | EJsonRuntimeNatSum => "natSum"
      | EJsonRuntimeNatArithMean => "natArithMean"
      | EJsonRuntimeFloatOfNat => "floatOfNat"
      | EJsonRuntimeFloatSum => "floatSum"
      | EJsonRuntimeFloatArithMean => "floatArithMean"
      | EJsonRuntimeFloatMin => "floatMin"
      | EJsonRuntimeFloatMax => "floatMax"
      | EJsonRuntimeNatOfFloat => "natOfFloat"
      | EJsonRuntimeForeign fop => toString fop
      end.

    Definition ejson_runtime_op_of_string (opname:string) : option ejson_runtime_op :=
      match opname with
      | "equal" => Some EJsonRuntimeEqual
      | "compare" => Some EJsonRuntimeCompare
      | "toString" => Some EJsonRuntimeToString
      | "toText" => Some EJsonRuntimeToText
      | "recConcat" => Some EJsonRuntimeRecConcat
      | "recMerge" => Some EJsonRuntimeRecMerge
      | "recRemove" => Some EJsonRuntimeRecRemove
      | "recProject" => Some EJsonRuntimeRecProject
      | "recDot" => Some EJsonRuntimeRecDot
      | "array" => Some EJsonRuntimeArray
      | "arrayLength" => Some EJsonRuntimeArrayLength
      | "arrayPush" => Some EJsonRuntimeArrayPush
      | "arrayAccess" => Some EJsonRuntimeArrayAccess
      | "either" => Some EJsonRuntimeEither
      | "toLeft" => Some EJsonRuntimeToLeft
      | "toRight" => Some EJsonRuntimeToRight
      | "unbrand" => Some EJsonRuntimeUnbrand
      | "cast" => Some EJsonRuntimeCast
      | "distinct" => Some EJsonRuntimeDistinct
      | "singleton" => Some EJsonRuntimeSingleton
      | "flatten" => Some EJsonRuntimeFlatten
      | "union" => Some EJsonRuntimeUnion
      | "minus" => Some EJsonRuntimeMinus
      | "min" => Some EJsonRuntimeMin
      | "max" => Some EJsonRuntimeMax
      | "nth" => Some EJsonRuntimeNth
      | "count" => Some EJsonRuntimeCount
      | "contains" => Some EJsonRuntimeContains
      | "sort" => Some EJsonRuntimeSort
      | "groupBy" => Some EJsonRuntimeGroupBy
      | "length" => Some EJsonRuntimeLength
      | "substring" => Some EJsonRuntimeSubstring
      | "substringEnd" => Some EJsonRuntimeSubstringEnd
      | "stringJoin" => Some EJsonRuntimeStringJoin
      | "like" => Some EJsonRuntimeLike
      | "natLt" => Some EJsonRuntimeNatLt
      | "natLe" => Some EJsonRuntimeNatLe
      | "natPlus" => Some EJsonRuntimeNatPlus
      | "natMinus" => Some EJsonRuntimeNatMinus
      | "natMult" => Some EJsonRuntimeNatMult
      | "natDiv" => Some EJsonRuntimeNatDiv
      | "natRem" => Some EJsonRuntimeNatRem
      | "natAbs" => Some EJsonRuntimeNatAbs
      | "natLog2" => Some EJsonRuntimeNatLog2
      | "natSqrt" => Some EJsonRuntimeNatSqrt
      | "natMinPair" => Some EJsonRuntimeNatMinPair
      | "natMaxPair" => Some EJsonRuntimeNatMaxPair
      | "natMin" => Some EJsonRuntimeNatMin
      | "natMax" => Some EJsonRuntimeNatMax
      | "natSum" => Some EJsonRuntimeNatSum
      | "natArithMean" => Some EJsonRuntimeNatArithMean
      | "floatOfNat" => Some EJsonRuntimeFloatOfNat
      | "floatSum" => Some EJsonRuntimeFloatSum
      | "floatArithMean" => Some EJsonRuntimeFloatArithMean
      | "floatMin" => Some EJsonRuntimeFloatMin
      | "floatMax" => Some EJsonRuntimeFloatMax
      | "natOfFloat" => Some EJsonRuntimeNatOfFloat
      | _ => lift EJsonRuntimeForeign (foreign_ejson_runtime_fromstring opname)
      end.

  Fixpoint defaultEJsonToString (j:@ejson foreign_ejson_model) : string
    := match j with
       | ejnull => "unit"%string
       | ejbigint n => toString n
       | ejnumber n => toString n
       | ejbool b => toString b
       | ejstring s => stringToString s
       | ejarray l => string_bracket
                        "["%string
                        (String.concat ", "%string
                                       (map defaultEJsonToString l))
                        "]"%string
       | ejobject ((s1,j')::nil) =>
         if (string_dec s1 "$left") then
           string_bracket
             "Left("%string
             (defaultEJsonToString j')
             ")"%string
         else if (string_dec s1 "$right") then
                string_bracket
                  "Right("%string
                  (defaultEJsonToString j')
                  ")"%string
              else
                string_bracket
                  "{"%string
                  (String.concat ", "%string
                                 (map (fun xy => let '(x,y):=xy in
                                                 (append (stringToString (key_decode x)) (append "->"%string
                                                                                                 (defaultEJsonToString y)))
                                      ) ((s1,j')::nil)))
                  "}"%string
      | ejobject ((s1,ejarray j1)::(s2,j2)::nil) =>
        if (string_dec s1 "$class") then
          if (string_dec s2 "$data") then
            match (ejson_brands j1) with
            | Some br =>
              (string_bracket
                 "<"
                 (append (@toString _ ToString_brands br) (append ":" (defaultEJsonToString j2)))
                 ">")
            | None =>
                string_bracket
                  "{"%string
                  (String.concat ", "%string
                                 ((append (stringToString (key_decode s1))
                                          (append "->"%string (string_bracket
                                                                 "["%string (String.concat ", "%string (map defaultEJsonToString j1)) "]"%string)))
                                    :: (append (stringToString (key_decode s2)) (append "->"%string (defaultEJsonToString j2)))
                                    :: nil))
                  "}"%string
            end
          else
            string_bracket
              "{"%string
              (String.concat ", "%string
                             ((append (stringToString (key_decode s1))
                                      (append "->"%string (string_bracket "["%string (String.concat ", "%string (map defaultEJsonToString j1)) "]"%string)))
                                :: (append (stringToString (key_decode s2)) (append "->"%string (defaultEJsonToString j2)))
                                :: nil))
              "}"%string
        else
          string_bracket
            "{"%string
            (String.concat ", "%string
                           ((append (stringToString (key_decode s1))
                                    (append "->"%string (string_bracket "["%string (String.concat ", "%string (map defaultEJsonToString j1)) "]"%string)))
                              :: (append (stringToString (key_decode s2)) (append "->"%string (defaultEJsonToString j2)))
                              :: nil))
            "}"%string
      | ejobject r =>
        string_bracket
          "{"%string
          (String.concat ", "%string
                         (map (fun xy => let '(x,y):=xy in
                                         (append (stringToString (key_decode x)) (append "->"%string (defaultEJsonToString y)))
                              ) r))
          "}"%string
       | ejforeign fd => toString fd
       end.
    
  End Util.

  Section Evaluation.
    Context (h:brand_relation_t).
    Definition ejson_runtime_eval (rt:ejson_runtime_op) (dl:list ejson) : option ejson :=
      match rt with
      | EJsonRuntimeEqual =>
        apply_binary (fun d1 d2 => if ejson_eq_dec d1 d2 then Some (ejbool true) else Some (ejbool false)) dl
      | EJsonRuntimeCompare =>
        apply_binary
          (fun d1 d2 =>
             match d1, d2 with
             | ejnumber n1, ejnumber n2 =>
               if float_lt n1 n2
               then
                 Some (ejnumber float_one)
               else if float_gt n1 n2
                    then
                      Some (ejnumber float_neg_one)
                    else
                      Some (ejnumber float_zero)
             | ejbigint n1, ejbigint n2 =>
               if Z_lt_dec n1 n2
               then
                 Some (ejnumber float_one)
               else if Z_gt_dec n1 n2
                    then
                      Some (ejnumber float_neg_one)
                    else
                      Some (ejnumber float_zero)
             | _, _ => None
             end) dl
      | EJsonRuntimeToString =>
        apply_unary
          (fun d =>
             Some (ejstring (foreign_ejson_runtime_tostring d))
          ) dl
      | EJsonRuntimeToText =>
        apply_unary
          (fun d =>
             Some (ejstring (foreign_ejson_runtime_totext d))
          ) dl
      | EJsonRuntimeRecConcat =>
        apply_binary
          (fun d1 d2 =>
             match ejson_is_record d1, ejson_is_record d2 with
             | Some r1, Some r2 => Some (ejobject (rec_sort (r1++r2)))
             | _, _ => None
             end) dl
      | EJsonRuntimeRecMerge =>
        apply_binary
          (fun d1 d2 =>
             match ejson_is_record d1, ejson_is_record d2 with
             | Some r1, Some r2 =>
               match @merge_bindings ejson _ ejson_eq_dec r1 r2 with
               | Some x => Some (ejarray ((ejobject x) :: nil))
               | None => Some (ejarray nil)
               end
             | _, _ => None
             end) dl
      | EJsonRuntimeRecRemove =>
        apply_binary
          (fun d1 d2 =>
             match ejson_is_record d1 with
             | Some r =>
               match d2 with
               | ejstring s =>
                 Some (ejobject (rremove r s))
               | _ => None
               end
             | _ => None
             end) dl
      | EJsonRuntimeRecProject =>
        apply_binary
          (fun d1 d2 =>
             match ejson_is_record d1 with
             | Some r =>
               match d2 with
               | ejarray sl =>
                 lift ejobject
                      (lift (rproject r)
                            (of_string_list sl))
               | _ => None
               end
             | _ => None
             end) dl
      | EJsonRuntimeRecDot =>
        apply_binary
          (fun d1 d2 =>
             match ejson_is_record d1 with
             | Some r =>
               match d2 with
               | ejstring s =>
                 edot r s
               | _ => None
               end
             | _ => None
             end) dl
      | EJsonRuntimeArray =>
        Some (ejarray dl)
      | EJsonRuntimeArrayLength =>
        apply_unary
          (fun d =>
             match d with
             | ejarray ja => Some (ejbigint (Z_of_nat (List.length ja)))
             | _ => None
             end) dl
      | EJsonRuntimeArrayPush =>
        apply_binary
          (fun d1 d2 =>
             match d1 with
             | ejarray ja => Some (ejarray (ja ++ (d2::nil)))
             | _ => None
             end) dl
      | EJsonRuntimeArrayAccess =>
        apply_binary
          (fun d1 d2 =>
             match d1, d2 with
             | ejarray ja, ejbigint n =>
               let natish := ZToSignedNat n in
               if (fst natish) then
                 match List.nth_error ja (snd natish) with
                 | None => None
                 | Some d => Some d
                 end
               else None
             | _, _ => None
             end) dl
      | EJsonRuntimeEither =>
        apply_unary
          (fun d =>
             match d with
             | ejobject (("$left", _)::nil) => Some (ejbool true)
             | ejobject (("$right",_)::nil) => Some (ejbool false)
             | _ => None
             end) dl
      | EJsonRuntimeToLeft =>
        apply_unary
          (fun d =>
             match d with
             | ejobject (("$left", d)::nil) => Some d
             | _ => None
             end) dl
      | EJsonRuntimeToRight =>
        apply_unary
          (fun d =>
             match d with
             | ejobject (("$right", d)::nil) => Some d
             | _ => None
             end) dl
      | EJsonRuntimeUnbrand =>
        apply_unary
          (fun d =>
             match d with
             | ejobject ((s,ejarray jl)::(s',j')::nil) =>
               if (string_dec s "$class") then
                 if (string_dec s' "$data") then
                   match ejson_brands jl with
                   | Some _ => Some j'
                   | None => None
                   end
                 else None
               else None
             | _ => None
             end) dl
      | EJsonRuntimeCast =>
        apply_binary
          (fun d1 d2 : ejson =>
             match d1 with
             | ejarray jl1 =>
               match ejson_brands jl1 with
               | Some b1 =>
                 match d2 with
                 | ejobject ((s,ejarray jl2)::(s',_)::nil) =>
                   if (string_dec s "$class") then
                     if (string_dec s' "$data") then
                       match ejson_brands jl2 with
                       | Some b2 =>
                         if (sub_brands_dec h b2 b1)
                         then
                           Some (ejobject (("$left"%string,d2)::nil))
                         else
                           Some (ejobject (("$right"%string,ejnull)::nil))
                       | None => None
                       end
                     else None
                   else None
                 | _ => None
                 end
               | None => None
               end
             | _ => None
             end) dl

      | EJsonRuntimeDistinct =>
        apply_unary
          (fun d =>
             match d with
             | ejarray l =>
               Some (ejarray (@bdistinct ejson ejson_eq_dec l))
             | _ => None
             end)
          dl
      | EJsonRuntimeSingleton =>
        apply_unary
          (fun d =>
             match d with
             | ejarray (d::nil) => Some (ejobject (("$left",d)::nil))
             | ejarray _ => Some (ejobject (("$right",ejnull)::nil))
             | _ => None
             end) dl
      | EJsonRuntimeFlatten =>
        apply_unary
          (fun d =>
             match d with
             | ejarray l =>
               lift ejarray (jflatten l)
             | _ => None
             end) dl
      | EJsonRuntimeUnion =>
        apply_binary
          (fun d1 d2 =>
             match d1, d2 with
             | ejarray l1, ejarray l2 =>
               Some (ejarray (bunion l1 l2))
             | _, _ => None
             end
          ) dl
      | EJsonRuntimeMinus =>
        apply_binary
          (fun d1 d2 =>
             match d1, d2 with
             | ejarray l1, ejarray l2 =>
               Some (ejarray (bminus l2 l1))
             | _, _ => None
             end
          ) dl
      | EJsonRuntimeMin =>
        apply_binary
          (fun d1 d2 =>
             match d1, d2 with
             | ejarray l1, ejarray l2 =>
               Some (ejarray (bmin l1 l2))
             | _, _ => None
             end
          ) dl
      | EJsonRuntimeMax =>
        apply_binary
          (fun d1 d2 =>
             match d1, d2 with
             | ejarray l1, ejarray l2 =>
               Some (ejarray (bmax l1 l2))
             | _, _ => None
             end
          ) dl
      | EJsonRuntimeNth =>
        apply_binary
          (fun d1 d2 =>
             match d1, d2 with
             | (ejarray c), (ejbigint n) =>
               let natish := ZToSignedNat n in
               if (fst natish) then
                 match List.nth_error c (snd natish) with
                 | Some d => Some (ejobject (("$left",d)::nil))
                 | None => Some (ejobject (("$right",ejnull)::nil))
                 end
               else Some (ejobject (("$right",ejnull)::nil))
             | _, _ => None
             end) dl
      | EJsonRuntimeCount =>
        apply_unary
          (fun d =>
             match d with
             | ejarray l => Some (ejbigint (Z_of_nat (bcount l)))
             | _ => None
             end) dl
      | EJsonRuntimeContains =>
        apply_binary
          (fun d1 d2 =>
             match d2 with
             | ejarray l =>
               if in_dec ejson_eq_dec d1 l
               then Some (ejbool true) else Some (ejbool false)
             | _ => None
             end) dl
      | EJsonRuntimeSort =>
        apply_binary
          (fun d1 d2 =>
             match d1 with
             | ejarray l1 =>
               ejson_sort (map ejson_get_criteria l1) d2
             | _ => None
             end) dl
      | EJsonRuntimeGroupBy =>
        apply_ternary
          (fun d1 d2 d3 =>
             match d3 with
             | ejarray l =>
               match d1 with
               | ejstring g =>
                 match d2 with
                 | ejarray sl =>
                   match of_string_list sl with
                   | Some kl =>
                     lift ejarray (ejson_group_by_nested_eval_table g kl l)
                   | None => None
                   end
                 | _ => None
                 end
               | _ => None
               end
             | _ => None
             end) dl
      | EJsonRuntimeLength =>
        apply_unary
          (fun d =>
             match d with
             | ejstring s => Some (ejbigint (Z_of_nat (String.length s)))
             | _ => None
             end) dl
      | EJsonRuntimeSubstring =>
        apply_ternary
          (fun d1 d2 d3 =>
             match d1, d2, d3 with
             | ejstring s, ejbigint start, ejbigint len =>
               let real_start :=
                   (match start with
                    | 0%Z => 0
                    | Z.pos p => Pos.to_nat p
                    | Z.neg n => (String.length s) - (Pos.to_nat n)
                    end) in
               let real_len :=
                   match len with
                   | 0%Z => 0
                   | Z.pos p => Pos.to_nat p
                   | Z.neg n => 0
                   end
               in
               Some (ejstring (substring real_start real_len s))
             | _, _, _ => None
             end) dl
      | EJsonRuntimeSubstringEnd =>
        apply_binary
          (fun d1 d2 =>
             match d1, d2 with
             | ejstring s, ejbigint start =>
               let real_start :=
                   (match start with
                    | 0%Z => 0
                    | Z.pos p => Pos.to_nat p
                    | Z.neg n => (String.length s) - (Pos.to_nat n)
                    end) in
               let real_len := (String.length s) - real_start in
               Some (ejstring (substring real_start real_len s))
             | _, _ => None
             end) dl
      | EJsonRuntimeStringJoin =>
        apply_binary
          (fun d1 d2 =>
             match d1, d2 with
             | ejstring sep, ejarray l =>
               match ejson_strings l with
               | Some sl => Some (ejstring (String.concat sep sl))
               | None => None
               end
             | _, _ => None
             end
          ) dl
      | EJsonRuntimeLike =>
        apply_binary
          (fun d1 d2 =>
             match d1, d2 with
             | ejstring sreg, ejstring starget =>
               Some (ejbool (string_like starget sreg None))
             | _, _ => None
             end
          ) dl
      | EJsonRuntimeNatLt =>
        apply_binary
          (fun d1 d2 =>
             match d1, d2 with
             | ejbigint n1, ejbigint n2 =>
               Some (ejbool (if Z_lt_dec n1 n2 then true else false))
             | _, _ => None
             end
          ) dl
      | EJsonRuntimeNatLe =>
        apply_binary
          (fun d1 d2 =>
             match d1, d2 with
             | ejbigint n1, ejbigint n2 =>
               Some (ejbool (if Z_le_dec n1 n2 then true else false))
             | _, _ => None
             end
          ) dl
      | EJsonRuntimeNatPlus =>
        apply_binary
          (fun d1 d2 =>
             match d1, d2 with
             | ejbigint n1, ejbigint n2 =>
               Some (ejbigint (Z.add n1 n2))
             | _, _ => None
             end
          ) dl
      | EJsonRuntimeNatMinus =>
        apply_binary
          (fun d1 d2 =>
             match d1, d2 with
             | ejbigint n1, ejbigint n2 =>
               Some (ejbigint (Z.sub n1 n2))
             | _, _ => None
             end
          ) dl
      | EJsonRuntimeNatMult =>
        apply_binary
          (fun d1 d2 =>
             match d1, d2 with
             | ejbigint n1, ejbigint n2 =>
               Some (ejbigint (Z.mul n1 n2))
             | _, _ => None
             end
          ) dl
      | EJsonRuntimeNatDiv =>
        apply_binary
          (fun d1 d2 =>
             match d1, d2 with
             | ejbigint n1, ejbigint n2 =>
               Some (ejbigint (Z.quot n1 n2))
             | _, _ => None
             end
          ) dl
      | EJsonRuntimeNatRem =>
        apply_binary
          (fun d1 d2 =>
             match d1, d2 with
             | ejbigint n1, ejbigint n2 =>
               Some (ejbigint (Z.rem n1 n2))
             | _, _ => None
             end
          ) dl
      | EJsonRuntimeNatAbs =>
        apply_unary
          (fun d =>
             match d with
             | ejbigint z => Some (ejbigint (Z.abs z))
             | _ => None
             end) dl
      | EJsonRuntimeNatLog2 =>
        apply_unary
          (fun d =>
             match d with
             | ejbigint z => Some (ejbigint (Z.log2 z))
             | _ => None
             end) dl
      | EJsonRuntimeNatSqrt =>
        apply_unary
          (fun d =>
             match d with
             | ejbigint z => Some (ejbigint (Z.sqrt z))
             | _ => None
             end) dl
      | EJsonRuntimeNatMinPair =>
        apply_binary
          (fun d1 d2 =>
             match d1, d2 with
             | ejbigint n1, ejbigint n2 =>
               Some (ejbigint (Z.min n1 n2))
             | _, _ => None
             end
          ) dl
      | EJsonRuntimeNatMaxPair =>
        apply_binary
          (fun d1 d2 =>
             match d1, d2 with
             | ejbigint n1, ejbigint n2 =>
               Some (ejbigint (Z.max n1 n2))
             | _, _ => None
             end
          ) dl
      | EJsonRuntimeNatSum =>
        apply_unary
          (fun d =>
             match d with
             | ejarray l =>
               match ejson_bigints l with
               | Some zl =>
                 Some (ejbigint (fold_right Zplus 0%Z zl))
               | None => None
               end
             | _ => None
             end) dl
      | EJsonRuntimeNatMin =>
        apply_unary
          (fun d =>
             match d with
             | ejarray l =>
               match ejson_bigints l with
               | Some zl =>
                 Some (ejbigint (bnummin zl))
               | None => None
               end
             | _ => None
             end) dl
      | EJsonRuntimeNatMax =>
        apply_unary
          (fun d =>
             match d with
             | ejarray l =>
               match ejson_bigints l with
               | Some zl =>
                 Some (ejbigint (bnummax zl))
               | None => None
               end
             | _ => None
             end) dl
      | EJsonRuntimeNatArithMean =>
        apply_unary
          (fun d =>
             match d with
             | ejarray l =>
               let length := List.length l in
               match ejson_bigints l with
               | Some zl =>
                 Some (ejbigint (Z.quot (fold_right Zplus 0%Z zl) (Z_of_nat length)))
               | None => None
               end
             | _ => None
             end) dl
      | EJsonRuntimeFloatOfNat =>
        apply_unary
          (fun d =>
             match d with
             | ejbigint n => Some (ejnumber (float_of_int n))
             | _ => None
             end) dl
      | EJsonRuntimeFloatSum =>
        apply_unary
          (fun d =>
             match d with
             | ejarray l =>
               match ejson_numbers l with
               | Some nl =>
                 Some (ejnumber (float_list_sum nl))
               | None => None
               end
             | _ => None
             end) dl
      | EJsonRuntimeFloatArithMean =>
        apply_unary
          (fun d =>
             match d with
             | ejarray l =>
               match ejson_numbers l with
               | Some nl =>
                 Some (ejnumber (float_list_arithmean nl))
               | None => None
               end
             | _ => None
             end) dl
      | EJsonRuntimeFloatMin =>
        apply_unary
          (fun d =>
             match d with
             | ejarray l =>
               match ejson_numbers l with
               | Some nl =>
                 Some (ejnumber (float_list_min nl))
               | None => None
               end
             | _ => None
             end) dl
      | EJsonRuntimeFloatMax =>
        apply_unary
          (fun d =>
             match d with
             | ejarray l =>
               match ejson_numbers l with
               | Some nl =>
                 Some (ejnumber (float_list_max nl))
               | None => None
               end
             | _ => None
             end) dl
      | EJsonRuntimeNatOfFloat =>
        apply_unary
          (fun d =>
             match d with
             | ejnumber f => Some (ejbigint (float_truncate f))
             | _ => None
             end) dl
      | EJsonRuntimeForeign fop =>
        foreign_ejson_runtime_op_interp fop dl
      end.
  End Evaluation.
End EJsonRuntimeOperators.