5

Sys.argv.(1)計算を実行し、結果を stdout に出力する単純なコマンドライン OCaml アプリケーションがあります。を使用してJavascriptにコンパイルできますが、未定義であることjs_of_ocamlに関する多くのエラーが発生します。caml_ml_output_charprintfs をスタブ化してこれらのエラーを修正したため、実行されますが、実行中に Firefox がフリーズします。

単純な OCaml コマンドライン スクリプトを Javascript ベースの Web ページにきれいにコンパイルするにはどうすればよいですか? フォークされたバージョンを維持したり、ブラウザーをフリーズしたりせずに?

4

2 に答える 2

3

UI スレッドで Javascript の協調マルチタスキングを中心に設計されていないソフトウェアを実行すると、ブラウザーがロックアップする可能性があるため、おそらく webworker を使用することをお勧めします。次のヘッダーを OCaml ファイルの先頭に追加して、通常の OCaml Sys と print の実装をオーバーロードできます。

(* JsHeader.ml *)
let output_buffer_ = Buffer.create 1000
let flush x=let module J = Js.Unsafe in let () = J.call 
        (J.variable "postMessage") (J.variable "self")
        [|J.inject (Js.string (Buffer.contents output_buffer_))|]
     in Buffer.clear output_buffer_

let print_string = Buffer.add_string output_buffer_
let print_char = Buffer.add_char output_buffer_
let print_newline () = print_char '\n'
let print_endline s = print_string (s^"\n"); flush ()
let caml_ml_output_char = print_char
let printf fmt = Printf.bprintf output_buffer_ fmt
module Printf = struct
    include Printf
    let printf fmt = Printf.bprintf output_buffer_ fmt
end

コマンドライン引数を渡す最も自然な方法は、Web ワーカーに送信される URL を使用することです。Ocaml Sys モジュールをオーバーライドして、代わり?argvに null で終了する文字列のシーケンスとして読み取ることができます。

module Sys = struct
    let char_split delim s = (*Str.split is overkill*)
        let hd = ref "" in let l = ref [] in 
        String.iter (fun c -> 
            if c = delim
            then  (l := (!hd)::(!l); hd := "")
            else hd := (!hd) ^ (String.make 1 c)
        ) s;
        List.rev ((!hd)::(!l)) 
    let getenv x = List.assoc x Url.Current.arguments
    let argv = Array.of_list (char_split '\x00' (getenv "?argv"))
    let executable_name = argv.(0)
end

ヘッダーを入力したので、簡単な OCaml コマンド ライン プログラムを入力できます。

(* cli.ml *)
let _ = print_string (Array.fold_left (^) "" (Array.make 40 (String.lowercase (Sys.argv.(1)^"\n"))) )

このコマンド ライン プログラムは OS に依存して出力をフラッシュしますが、手動で出力をフラッシュする必要があります。コマンドが終了したことを Javascript が認識できるように、null 文字を送信することもできます。これは、次のフッターを追加することで実現できます。

(* JsFooter.ml *)
let _ = flush stdout; print_endline "\x00" 

ファイルを結合して、次のようにコンパイルできます。

 cat JsHeader.ml cli.ml JsFooter.ml > merged.ml
 ocamlbuild -use-menhir -menhir "menhir" \
   -pp "camlp4o -I /opt/local/lib/ocaml/site-lib js_of_ocaml/pa_js.cmo" \
   -cflags -I,+js_of_ocaml,-I,+site-lib/js_of_ocaml -libs js_of_ocaml \
   -lflags -I,+js_of_ocaml,-I,+site-lib/js_of_ocaml merged.byte
 js_of_ocaml merged.byte

ファイル merged.js を作成したので、JavaScript を次のような単純な Web ページにラップできます。

<html>
<head>
<meta http-equiv="Content-Type" content="text/xhtml+xml; charset=UTF-8" />
<title>ml2js sample_cli</title>
<script type="text/javascript">
<!--
var worker;
function go () {
  var output=document.getElementById ("output");
  var argv = encodeURIComponent("/bin/sample_cli\0"+document.getElementById ("input").value);
  if (worker) {
    worker.terminate();
  }
  worker = new Worker ("sample_cli.js?argv="+argv);
  document.getElementById ("output").value="";
  worker.onmessage = function (m) {
    if (typeof m.data == 'string') {
    if (m.data == "\0\n") {
        output.scrollTop = output.scrollHeight
    } else {
        output.value+=m.data;
    }
    }
  }
}
//-->
</script>
</head>

<body onload=go()>
<textarea id="input" rows="2" cols="60" onkeyup="go()" onchange="go()" style="width:90%">SAMPLE_INPUT</textarea> 
<button onclick="go()">go</button><br>
<textarea id="output" rows="0" cols="60" style="width:100%;height:90%" readonly onload=go()>
Your browser does not seem to support Webworkers.
Try Firefox, Chrome or IE10+. 
</textarea>
</body>

</html>

このアプローチの実際の例については、http: //www.dansted.org/app/bctl-plain.html とhttps://github.com/gmatht/TimeLogicUnify/blob/master/ATL/js/webworker/を参照してください。適切なヘッダー、フッターなどを追加するスクリプトのml2js.sh 。

于 2016-05-28T06:19:01.253 に答える
1

js_of_ocaml のどのバージョンを使用していますか? caml_ml_output_char でエラーが発生することはありません。ノードで実行する場合、sys.argv を正しく設定する必要があります。ブラウザーでは、Sys.argv が [|"a.out"|] に設定されます。これでまだ問題がある場合は、 https://github.com/ocsigen/js_of_ocaml/issues/newで GitHub の問題を開いてください。

于 2016-05-30T19:31:09.393 に答える