on master help sign in
Merge branch 'master' into tcl
commit598da6a37776bb7d76ebdc7ed8f11c5e74799bd9 authorMason Clayton <mason@turb.io> dateMon 4 Mar 2019, 16:08 (8 years ago) parent9f066731fa4bf5
13 files changed+365−5
Dockerfile+13−2 README.md+2−1 languages/ocaml/README.md+24 languages/ocaml/main.go+71 languages/ocaml/repl.ml+189 scripts/gofiles.sh+2−2 tests/ocaml/code_print.exp+6 tests/ocaml/exception.exp+10 tests/ocaml/expr.exp+6 tests/ocaml/not_quiet.exp+9 tests/ocaml/ps1.exp+9 tests/ocaml/ps2.exp+14 tests/ocaml/quiet.exp+10
Dockerfile+13−2
@@ -13,7 +13,9 @@ RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y \
1313 libnspr4-dev \
1414 libffi-dev \
1515 expect \
16− nodejs
16+ nodejs \
17+ m4 \
18+ software-properties-common
1719
1820RUN wget http://launchpadlibrarian.net/309343864/libmozjs185-dev_1.8.5-1.0.0+dfsg-7_amd64.deb && \
1921 wget http://launchpadlibrarian.net/309343863/libmozjs185-1.0_1.8.5-1.0.0+dfsg-7_amd64.deb && \
@@ -38,6 +40,14 @@ WORKDIR /gocode/src/github.com/replit/prybar
3840
3941RUN cp languages/tcl/tcl.pc /usr/lib/pkgconfig/
4042
43+# OCaml / Reason stuff
44+RUN add-apt-repository ppa:avsm/ppa && \
45+ apt-get update && \
46+ apt-get install ocaml opam -y && \
47+ opam init -c ocaml-system -n --disable-sandboxing && \
48+ eval `opam env` && \
49+ echo "eval \`opam env\`" >> ~/.bashrc
50+
4151RUN make \
4252 prybar-python2 \
4353 prybar-python3 \
@@ -46,7 +56,8 @@ RUN make \
4656 prybar-spidermonkey \
4757 prybar-nodejs \
4858 prybar-julia \
49− prybar-tcl
59+ prybar-tcl \
60+ prybar-ocaml
5061
5162ENV LC_ALL=C.UTF-8
5263
README.md+2−1
@@ -42,6 +42,7 @@ Usage of ./prybar-language:
4242| Javascript (spidermonkey) | ✔ | ✗ | ✗ | ✗ | ✗ | - |
4343| Javascript (nodejs) | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
4444| Julia | ✔ | ✗ | ✔ | ✔ | ✗ | ✔ |
45+| OCaml | ✔ | ✔ | ✗ | ✔ | ✗ | ✔ |
4546
4647## Building
4748
@@ -54,7 +55,7 @@ See [Dockerfile](Dockerfile) for hints what packages to install on linux.
5455### OSX
5556
5657```
57−brew install go r ruby python python@2 lua spidermonkey
58+brew install go r ruby python python@2 lua spidermonkey opam
5859```
5960
6061## Docker
languages/ocaml/README.mdnew file+24
@@ -0,0 +1,24 @@
1+# OCaml / Reason interpreter
2+
3+** Usage: **
4+```
5+ocaml repl.ml --help
6+OCaml / Reason repl script for prybar. Options available:
7+ -q Don't print OCaml version on startup
8+ -e Eval and output results of interpreted code
9+ -c Run code without printing the output
10+ -i Run as interactive repl
11+ -s {ml|re} Sets the syntax for the repl (default: ml)
12+ -help Display this list of options
13+ --help Display this list of options
14+```
15+
16+** Usage examples: **
17+
18+```
19+# Run some ocaml code
20+ocaml repl.ml -e "let foo = 1;;"
21+
22+# Run some reason code
23+ocaml repl.ml -s re -e "let foo = 1;"
24+```
languages/ocaml/main.gonew file+71
@@ -0,0 +1,71 @@
1+// OCaml main
2+package main
3+
4+//go:generate ../../scripts/gofiles.sh generated_files.go
5+
6+import (
7+ "github.com/replit/prybar/utils"
8+ "io/ioutil"
9+ "os"
10+ "os/exec"
11+ "syscall"
12+)
13+
14+func findHelper(path string) string {
15+ bytes, err := File(path + ".ml")
16+ if bytes != nil {
17+ f, err := ioutil.TempFile("", "prybar-ocaml-*.ml")
18+ if err != nil {
19+ panic(err)
20+ }
21+
22+ if _, err = f.Write(bytes); err != nil {
23+ panic(err)
24+ }
25+ if err = f.Close(); err != nil {
26+ panic(err)
27+ }
28+ return f.Name()
29+ }
30+ if err != nil {
31+ panic(err)
32+ }
33+ panic("File not found: " + path + ".ml")
34+}
35+
36+func Execute(config *utils.Config) {
37+ path, err := exec.LookPath("ocaml")
38+
39+ if err != nil {
40+ panic(err)
41+ }
42+
43+ env := os.Environ()
44+ args := []string{"ocaml", findHelper("repl"), "-s", "ml"}
45+
46+ if config.Quiet {
47+ args = append(args, "-q")
48+ }
49+
50+ if config.Code != "" {
51+ args = append(args, "-c", config.Code)
52+ } else if config.Exp != "" {
53+ args = append(args, "-e", config.Exp)
54+ } else if (config.Interactive || config.OurInteractive) {
55+ args = append(args, "-i")
56+ }
57+
58+ if config.Ps1 != "" {
59+ env = append(env, "PRYBAR_PS1="+config.Ps1)
60+ }
61+
62+ if config.Ps2 != "" {
63+ env = append(env, "PRYBAR_PS2="+config.Ps2)
64+ }
65+
66+ if config.Args != nil && len(config.Args) > 0 {
67+ args = append(args, config.Args...)
68+ }
69+
70+ syscall.Exec(path, args, env)
71+}
languages/ocaml/repl.mlnew file+189
@@ -0,0 +1,189 @@
1+#use "topfind";;
2+#require "compiler-libs";;
3+#require "unix";;
4+(*#require "reason";;*)
5+#load "ocamlcommon.cma";;
6+#load "unix.cma";;
7+(*#load "reason.cma";;*)
8+
9+type syntax = Reason | OCaml
10+
11+type eval_result = Success | Error of string
12+
13+type mode =
14+ | RunCode of string * syntax
15+ | StartRepl of syntax
16+ | PrintExpression of string * syntax
17+ | Stdin of syntax
18+ | Invalid of string
19+
20+type args = {mode: mode}
21+
22+exception LangException of string
23+
24+let _ =
25+ let quiet = ref false in
26+ let syntax = ref OCaml in
27+ let interactive_mode = ref false in
28+ let print_mode = ref false in
29+ let run_mode = ref false in
30+ let ps1 = Sys.getenv_opt "PRYBAR_PS1" |> function | Some str -> str | None -> "#" in
31+ let ps2 = Sys.getenv_opt "PRYBAR_PS2" |> function | Some str -> str | None -> " " in
32+ (* If there is code provided to interpret *)
33+ let code = ref "" in
34+ let parse_syntax = function
35+ | "re" -> syntax := Reason
36+ | "ml" -> syntax := OCaml
37+ | arg -> raise (Arg.Bad ("Unknown syntax: " ^ arg))
38+ in
39+ (*let string_of_syntax = function OCaml -> "ml" | Reason -> "re" in*)
40+ let print_mode_arg str =
41+ print_mode := true ;
42+ code := str
43+ in
44+ let run_mode_arg str =
45+ run_mode := true ;
46+ code := str
47+ in
48+ let speclist =
49+ [ ("-q", Arg.Set quiet, "Don't print OCaml version on startup")
50+ ; ( "-e" , Arg.String print_mode_arg , "Eval and output results of interpreted code" )
51+ ; ("-c", Arg.String run_mode_arg, "Run code without printing the output")
52+ ; ("-i", Arg.Set interactive_mode, "Run as interactive repl")
53+ ; ( "-s" , Arg.Symbol (["ml"; "re"], parse_syntax), " Sets the syntax for the repl (default: ml)" ) ]
54+ in
55+ let usage_msg =
56+ "OCaml / Reason repl script for prybar. Options available:"
57+ in
58+ Arg.parse speclist
59+ (fun str -> print_endline ("Anonymous arg: " ^ str))
60+ usage_msg ;
61+ let mode =
62+ match (!print_mode, !run_mode, !interactive_mode) with
63+ | true, false, false -> PrintExpression (!code, !syntax)
64+ | false, true, false -> RunCode (!code, !syntax)
65+ | false, false, true -> StartRepl !syntax
66+ | _ -> Invalid "You can only use one mode: -e | -i | -c"
67+ in
68+ let module Custom_Toploop = struct
69+ include Toploop
70+ open Format
71+
72+ (* Most stuff is straightly copied and modified
73+ * from github.com/ocaml/ocaml/blob/trunk/toplevel/toploop.ml *)
74+ exception PPerror
75+
76+ let first_line = ref true
77+
78+ let got_eof = ref false
79+
80+ let refill_lexbuf buffer len =
81+ if !got_eof then (
82+ got_eof := false ;
83+ 0 )
84+ else
85+ let prompt =
86+ if !first_line then ps1 ^ " "
87+ else if Lexer.in_comment () then "* "
88+ else ps2 (* continuation prompt *)
89+ in
90+ first_line := false ;
91+ let len, eof = !read_interactive_input prompt buffer len in
92+ if eof then (
93+ Location.echo_eof () ;
94+ if len > 0 then got_eof := true ;
95+ len )
96+ else len
97+
98+ let loop ppf =
99+ Clflags.debug := true ;
100+ Location.formatter_for_warnings := ppf ;
101+ ( try initialize_toplevel_env () with
102+ | (Env.Error _ | Typetexp.Error _) as exn ->
103+ Location.report_exception ppf exn ;
104+ exit 2 ) ;
105+ let lb = Lexing.from_function refill_lexbuf in
106+ Location.init lb "//toplevel//" ;
107+ Location.input_name := "//toplevel//" ;
108+ Location.input_lexbuf := Some lb ;
109+ Sys.catch_break true ;
110+ (*load_ocamlinit ppf;*)
111+ while true do
112+ let snap = Btype.snapshot () in
113+ try
114+ Lexing.flush_input lb ;
115+ Location.reset () ;
116+ Warnings.reset_fatal () ;
117+ first_line := true ;
118+ let phr =
119+ try !parse_toplevel_phrase lb with Exit -> raise PPerror
120+ in
121+ let phr = preprocess_phrase ppf phr in
122+ Env.reset_cache_toplevel () ;
123+ ignore (execute_phrase true ppf phr)
124+ with
125+ | End_of_file -> exit 0
126+ | Sys.Break ->
127+ fprintf ppf "Interrupted.@." ;
128+ Btype.backtrack snap
129+ | PPerror -> ()
130+ | x ->
131+ Location.report_exception ppf x ;
132+ Btype.backtrack snap
133+ done
134+ end in
135+ let module Repl = struct
136+ let std_fmt = Format.std_formatter
137+
138+ let noop_fmt = Format.make_formatter (fun _ _ _ -> ()) ignore
139+
140+ let init_toploop () =
141+ Topfind.add_predicates ["byte"; "toploop"] ;
142+ (* Add findlib path so Topfind is available and it won't be
143+ initialized twice if the user does [#use "topfind"]. *)
144+ Topdirs.dir_directory (Findlib.package_directory "findlib") ;
145+ Toploop.initialize_toplevel_env ()
146+
147+ let start_loop ?(fmt = std_fmt) () = Custom_Toploop.loop fmt
148+
149+ let eval ?(fmt = std_fmt) ~syntax str =
150+ try
151+ let lex = Lexing.from_string str in
152+ let tpl_phrases =
153+ match syntax with
154+ | OCaml | Reason -> Parse.use_file lex
155+ (*| Reason ->*)
156+ (*List.map Reason_toolchain.To_current.copy_toplevel_phrase*)
157+ (*(Reason_toolchain.RE.use_file lex)*)
158+ in
159+ let exec phr =
160+ if Toploop.execute_phrase true fmt phr then Success
161+ else Error "No result"
162+ in
163+ let rec execAll phrases =
164+ match phrases with
165+ | [] -> Error "No result"
166+ | [phr] -> exec phr
167+ | phr :: next -> (
168+ let ret = exec phr in
169+ match ret with Error _ -> ret | _ -> execAll next )
170+ in
171+ execAll tpl_phrases
172+ with
173+ | Syntaxerr.Error _ -> Error "Syntax Error occurred"
174+ (*| Reason_syntax_util.Error _ -> Error "Reason Parsing Error"*)
175+ | _ -> Error ("Error while exec: " ^ str)
176+ end in
177+ if not !quiet then print_endline ("OCaml " ^ Sys.ocaml_version ^ " on " ^ Sys.os_type);
178+ match mode with
179+ | PrintExpression (code, syntax) ->
180+ Repl.init_toploop () ;
181+ Repl.eval ~syntax code |> ignore
182+ | RunCode (code, syntax) ->
183+ Repl.init_toploop () ;
184+ Repl.eval ~syntax ~fmt:Repl.noop_fmt code |> ignore
185+ | StartRepl syntax ->
186+ Repl.init_toploop () ;
187+ Repl.start_loop ()
188+ | Stdin syntax -> print_endline "Reading from stdin"
189+ | Invalid str -> print_endline str
scripts/gofiles.sh+2−2
@@ -13,7 +13,7 @@ func File(name string) ([]byte, error) {
1313
1414EOF
1515
16−for fn in $(ls *.js); do
16+for fn in $(ls | egrep -i '.*\.(js|ml)'); do
1717
1818 echo " case \"$fn\":" >> $1
1919 echo " return base64.StdEncoding.DecodeString(\"$(base64 -i $fn | tr -d \\n)\")" >> $1
@@ -27,4 +27,4 @@ cat << EOF >> $1
2727}
2828EOF
2929
30−echo "Generated $(realpath $1)"
30+echo "Generated $(realpath $1)"
tests/ocaml/code_print.expnew file+6
@@ -0,0 +1,6 @@
1+#!/usr/bin/expect -f
2+
3+spawn ./prybar-ocaml -q -c "print_endline(\"hello world\")"
4+match_max 100000
5+expect -exact "hello world"
6+expect eof
tests/ocaml/exception.expnew file+10
@@ -0,0 +1,10 @@
1+#!/usr/bin/expect -f
2+
3+spawn ./prybar-ocaml -q -i
4+match_max 100000
5+expect -exact "--> "
6+send -- "raise (Invalid_argument \"doh\");;\r"
7+expect -exact "Exception: Invalid_argument \"doh\".\r
8+--> "
9+send -- ""
10+expect eof
tests/ocaml/expr.expnew file+6
@@ -0,0 +1,6 @@
1+#!/usr/bin/expect -f
2+
3+spawn ./prybar-ocaml -q -e 1+1
4+match_max 100000
5+expect -exact "- : int = 2"
6+expect eof
tests/ocaml/not_quiet.expnew file+9
@@ -0,0 +1,9 @@
1+#!/usr/bin/expect -f
2+
3+spawn ./prybar-ocaml -e 1+1
4+match_max 100000
5+
6+# OCaml 4.06.0 on Unix
7+expect -re "^OCaml (.*) on Unix"
8+expect -exact "- : int = 2"
9+expect eof
tests/ocaml/ps1.expnew file+9
@@ -0,0 +1,9 @@
1+#!/usr/bin/expect -f
2+
3+spawn ./prybar-ocaml -q -i -ps1 ">>"
4+match_max 100000
5+expect -exact ">>"
6+send -- "1+1;;\r"
7+expect -exact "- : int = 2"
8+send -- ""
9+expect eof
tests/ocaml/ps2.expnew file+14
@@ -0,0 +1,14 @@
1+#!/usr/bin/expect -f
2+
3+spawn ./prybar-ocaml -q -i -ps2 continuation
4+match_max 100000
5+expect -exact "--> "
6+send -- "let a =\r"
7+expect -exact "let a =\r
8+continuation"
9+send -- "print_endline(\"continued!\");;\r"
10+expect -exact "continued!\r
11+val a : unit = ()\r
12+-->"
13+send -- ""
14+expect eof
tests/ocaml/quiet.expnew file+10
@@ -0,0 +1,10 @@
1+#!/usr/bin/expect -f
2+
3+spawn ./prybar-ocaml -q -i
4+match_max 100000
5+expect -exact "--> "
6+send -- "1+1;;\r"
7+expect -exact "- : int = 2\r
8+--> "
9+send -- ""
10+expect eof