odn / ocaml / odn / n1.ml

let precision = 100

let make_tuple = function
  | Eterm.ET_tuple [|Eterm.ET_int n1; Eterm.ET_int n2; Eterm.ET_int n3;|] ->
    Some (Int32.to_int n1,
          Num.num_of_int (Int32.to_int n2),
          Int32.to_int n3)
  | Eterm.ET_tuple [|Eterm.ET_int n1; Eterm.ET_bignum n2; Eterm.ET_int n3;|] ->
    Some (Int32.to_int n1, n2, Int32.to_int n3)
  | _x ->
    None

let compose_num mant = function
  | pow when pow >= 0 ->
    let ipow = Big_int.power_int_positive_int 10 pow in
    let bpow = Num.Big_int ipow in
    Num.mult_num mant bpow
  | pow ->
    let ipow = Big_int.power_int_positive_int 10 (-pow) in
    let bpow = Num.Big_int ipow in
    Num.div_num mant bpow

let make_num = function
  | Some (0, mant, pow) ->
    Some (compose_num mant pow)
  | Some (1, mant, pow) ->
    Some (Num.minus_num (compose_num mant pow))
  | None ->
    None

let conv_sign = function
  | -1 -> 1
  | 0 -> 0
  | 1 -> 0
  | _ -> assert false (* should not happen *)

(* remove trailing zeroes from mantissa, reduce exponent accordingly *)
let short_decimal mant_str mant_len exp =
  let rec f str idx lexp =
    if idx > 0 && str.[idx] = '0' then
      f str (idx-1) (lexp+1)
    else
      idx, lexp
  in
  let idx, new_exp = f mant_str (mant_len-1) exp in
  let nstr = String.sub mant_str 0 (idx+1) in
  nstr, idx+1, new_exp

let create_decimal n =
  let sign = conv_sign (Num.sign_num n) in
  let str = Num.approx_num_exp precision n in
  let len = String.length str in
  (* how about length's complexity? According to Xavier Leroy: O(1) *)
  let mant_idx = String.index str '.' + 1 in
  let exp_idx = mant_idx + precision + 1 in (* +1 for 'e' *)
  let mant_str = String.sub str mant_idx precision in
  let exp_len = len - exp_idx in
  let exp_str = String.sub str exp_idx exp_len in
  let exp = int_of_string exp_str in
  let short_mant_str, short_mant_len, new_exp =
    short_decimal mant_str precision (exp-precision) in
  let mant = Big_int.big_int_of_string short_mant_str in
  sign, mant, new_exp

let make_decimal_tuple n =
  let sign, mant, exp = create_decimal n in
  Eterm.ET_tuple [|Eterm.ET_int (Int32.of_int sign);
                  Eterm.ET_bignum (Num.Big_int mant);
                  Eterm. ET_int (Int32.of_int exp);|]

let make_big_num = function
  | Eterm.ET_int x -> Num.num_of_int (Int32.to_int x)
  | Eterm.ET_bignum x -> x

let op_divide x1 x2 =
  let t1 = make_tuple x1 in
  let t2 = make_tuple x2 in
  match t1, t2 with
  | Some _, Some _ ->
    let (Some n1) = make_num t1 in
    let (Some n2) = make_num t2 in
    let res = Num.div_num n1 n2 in
    Eterm.ET_tuple [|(Eterm.ET_atom "ok"); make_decimal_tuple res;|]
  | _, _ ->
    Eterm.ET_tuple [|(Eterm.ET_atom "error"); (Eterm.ET_atom "wrong_arguments");|]

let op_subtract x1 x2 =
  let t1 = make_tuple x1 in
  let t2 = make_tuple x2 in
  match t1, t2 with
  | Some _, Some _ ->
    let (Some n1) = make_num t1 in
    let (Some n2) = make_num t2 in
    let res = Num.sub_num n1 n2 in
    Eterm.ET_tuple [|(Eterm.ET_atom "ok"); make_decimal_tuple res;|]
  | _, _ ->
    Eterm.ET_tuple [|(Eterm.ET_atom "error"); (Eterm.ET_atom "wrong_arguments");|]

let op_add x1 x2 =
  let t1 = make_tuple x1 in
  let t2 = make_tuple x2 in
  match t1, t2 with
  | Some _, Some _ ->
    let (Some n1) = make_num t1 in
    let (Some n2) = make_num t2 in
    let res = Num.add_num n1 n2 in
    Eterm.ET_tuple [|(Eterm.ET_atom "ok"); make_decimal_tuple res;|]
  | _, _ ->
    Eterm.ET_tuple [|(Eterm.ET_atom "error"); (Eterm.ET_atom "wrong_arguments");|]

let handle_payload = function
    | Eterm.ET_tuple [|(Eterm.ET_atom "divide"); x1; x2;|] ->
      Trace.dbg "handle_payload" "divide\n%!";
      op_divide x1 x2
    | Eterm.ET_tuple [|(Eterm.ET_atom "subtract"); x1; x2;|] ->
      Trace.dbg "handle_payload" "subtract\n%!";
      op_subtract x1 x2
    | Eterm.ET_tuple [|(Eterm.ET_atom "add"); x1; x2;|] ->
      Trace.dbg "handle_payload" "add\n%!";
      op_add x1 x2
    | Eterm.ET_tuple [|(Eterm.ET_atom "multiply"); Eterm.ET_bignum n1; Eterm.ET_bignum n2;|] ->
      Trace.dbg "handle_payload" "mult bignums\n%s\n%s\n%!"
        (Num.string_of_num n1) (Num.string_of_num n2);
      let res = Num.mult_num n1 n2 in
      Eterm.ET_bignum res
    | Eterm.ET_tuple [|(Eterm.ET_atom "mult_list"); Eterm.ET_list lst;|] ->
      Trace.dbg "handle_payload" "mult list\n%!";
      let f acc x =
        let bn = make_big_num x in
        Num.mult_num acc bn
      in
      let res = List.fold_left f (Num.num_of_int 1) lst in
      Eterm.ET_bignum res
    | Eterm.ET_tuple [|(Eterm.ET_atom "sum_list"); Eterm.ET_list lst;|] ->
      Trace.dbg "handle_payload" "sum list\n%!";
      let f acc x =
        let bn = make_big_num x in
        Num.add_num acc bn
      in
      let res = List.fold_left f (Num.num_of_int 0) lst in
      Eterm.ET_bignum res
    | other ->
      Trace.dbg "handle_payload" "other\n%s\n%!" (Eterm.to_string other);
      Eterm.ET_atom "error"

let create_main_process node name =
    let mbox = Enode.create_mbox node in
    let _ = Enode.register_mbox node mbox name in
    let recvCB = fun msg -> match msg with
    | Eterm.ET_tuple [|toPid; ref; (Eterm.ET_atom "stop");|] ->
      Trace.dbg "n1 worker" "stop message received\n%!";
      Enode.stop node;
      exit 0
    | Eterm.ET_tuple [|toPid; ref; (Eterm.ET_atom "ping");|] ->
      Trace.dbg "n1 worker" "ping received\n%!";
      Enode.send
        node
        toPid
        (Eterm.ET_tuple [| ref; Eterm.ET_atom "pong"; |])
    | Eterm.ET_tuple [|toPid; ref; payload;|] ->
      let res = handle_payload payload in
      Enode.send
        node
        toPid
        (Eterm.ET_tuple [| ref; res; |])
    | Eterm.ET_tuple [|toPid; ref; (Eterm.ET_atom "multiply"); Eterm.ET_bignum n1; Eterm.ET_bignum n2;|] ->
      Trace.dbg "n1 worker" "bignums\n%s\n%s\n%!"
        (Num.string_of_num n1) (Num.string_of_num n2);
      let res = Num.mult_num n1 n2 in
        Enode.send
            node
            toPid
            (Eterm.ET_tuple [| ref; Eterm.ET_bignum res; |])
    | _ ->
      Trace.dbg "n1 main"
        "unknown message\n%!";
        (* skip unknown message *)
        ()
    in
    Enode.Mbox.create_activity mbox recvCB

let doit () =
    try
        let name = ref "ocaml" in
        let cookie = ref "" in
        Arg.parse
            [
                ("-cookie", Arg.String ((:=) cookie), "erlang node cookie");
                ("-name", Arg.String ((:=) name), "erlang node name");
                ("-debug", Arg.Unit (fun () -> Trace.set_level Trace.lvl_debug), "print debug messages");
            ]
            ignore
            "";
        Trace.inf "Node_double" "Creating node; name: %s; cookie: %s\n" !name !cookie;
        let n = Enode.create !name ~cookie:!cookie in
        let _ = Thread.sigmask Unix.SIG_BLOCK [Sys.sigint] in
        let _ = Enode.start n in
        let _ = create_main_process n "byn" in
        let _ = Thread.wait_signal [Sys.sigint] in
        Enode.stop n
    with
        exn -> Printf.printf "ERROR:%s\n" (Printexc.to_string exn)

let _  = doit ()
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.