diff --git a/.ci-macosx.sh b/.ci-macosx.sh index ea6d44cb1..b793b0d7a 100644 --- a/.ci-macosx.sh +++ b/.ci-macosx.sh @@ -6,7 +6,7 @@ brew update brew install pkg-config brew install opam brew install libev -opam init -y --compiler=4.05.0 +opam init -y --compiler=4.12.0 eval $(opam env) opam install -y -j 2 . --deps-only --locked diff --git a/.github/workflows/static-builds.yml b/.github/workflows/static-builds.yml index 02b1c868c..a87fffebd 100644 --- a/.github/workflows/static-builds.yml +++ b/.github/workflows/static-builds.yml @@ -46,20 +46,16 @@ jobs: sw_vers system_profiler SPSoftwareDataType uname -a - # Need unreleased 2.1.0~rc - # - name: Retrieve opam - # run: | - # mkdir "$HOME/bin" - # wget https://github.com/ocaml/opam/releases/download/2.1.0-beta2/opam-2.1.0-beta2-x86_64-macos -O $HOME/bin/opam - # chmod a+x $HOME/bin/opam - # echo "$HOME/bin" >> $GITHUB_PATH - - name: Install latest opam + - name: Retrieve opam run: | - brew install opam --HEAD + mkdir "$HOME/bin" + wget https://github.com/ocaml/opam/releases/download/2.1.0/opam-2.1.0-x86_64-macos -O $HOME/bin/opam + chmod a+x $HOME/bin/opam + echo "$HOME/bin" >> $GITHUB_PATH - name: Prepare build environment run: | opam init -a --bare - opam switch create . ocaml-base-compiler 'dune<2' --deps-only + opam switch create . ocaml-base-compiler --deps-only - name: Build the binaries run: | opam exec -- make LINKING_MODE=static diff --git a/.gitignore b/.gitignore index 771207167..d24fb86af 100644 --- a/.gitignore +++ b/.gitignore @@ -6,14 +6,10 @@ _opam .opam-switch Makefile.local docker/ -src/ppx-metaquot/ast_lifter.ml learnocaml-server.byte learn-ocaml.install -src/grader/embedded_cmis.ml -src/grader/embedded_grading_cmis.ml - demo-repository/exercises/*.stderr demo-repository/exercises/*.stdout demo-repository/exercises/*.outcomes diff --git a/Dockerfile b/Dockerfile index bd280f5ad..b5ec76831 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,15 +1,15 @@ -FROM ocaml/opam:alpine-3.13-ocaml-4.05 as compilation +FROM ocaml/opam:alpine-3.13-ocaml-4.12 as compilation LABEL Description="learn-ocaml building" Vendor="OCamlPro" -WORKDIR learn-ocaml +WORKDIR /home/opam/learn-ocaml -COPY learn-ocaml.opam learn-ocaml.opam.locked learn-ocaml-client.opam ./ +COPY learn-ocaml.opam learn-ocaml.opam.locked learn-ocaml-client.opam learn-ocaml-client.opam.locked ./ RUN sudo chown -R opam:nogroup . ENV OPAMYES true RUN echo 'archive-mirrors: [ "https://opam.ocaml.org/cache" ]' >> ~/.opam/config \ && opam repository set-url default http://opam.ocaml.org \ - && opam switch 4.05 \ + && opam switch 4.12 \ && echo 'pre-session-commands: [ "sudo" "apk" "add" depexts ]' >> ~/.opam/config \ && opam install . --deps-only --locked @@ -42,7 +42,7 @@ WORKDIR /learnocaml COPY --from=compilation /home/opam/install-prefix/bin/learn-ocaml-client /usr/bin -ENTRYPOINT ["dumb-init","learn-ocaml-client"] +ENTRYPOINT ["dumb-init","/usr/bin/learn-ocaml-client"] LABEL org.opencontainers.image.title="learn-ocaml-client" LABEL org.opencontainers.image.description="learn-ocaml command-line client" @@ -68,7 +68,7 @@ WORKDIR /home/learn-ocaml COPY --from=compilation /home/opam/install-prefix /usr -ENTRYPOINT ["dumb-init","learn-ocaml","--sync-dir=/sync","--repo=/repository"] +ENTRYPOINT ["dumb-init","/usr/bin/learn-ocaml","--sync-dir=/sync","--repo=/repository"] CMD ["build","serve"] LABEL org.opencontainers.image.title="learn-ocaml" diff --git a/Dockerfile.test-client b/Dockerfile.test-client index ee7c49a13..32345200a 100644 --- a/Dockerfile.test-client +++ b/Dockerfile.test-client @@ -1,7 +1,7 @@ # This Dockerfile is useful for testing purposes # to ensure learn-ocaml-client can be built alone from learn-ocaml-client.opam -FROM ocaml/opam:alpine-3.13-ocaml-4.05 as compilation +FROM ocaml/opam:alpine-3.13-ocaml-4.12 as compilation LABEL Description="learn-ocaml building" Vendor="OCamlPro" WORKDIR learn-ocaml @@ -13,7 +13,7 @@ RUN sudo chown -R opam:nogroup . ENV OPAMYES true RUN echo 'archive-mirrors: [ "https://opam.ocaml.org/cache" ]' >> ~/.opam/config \ && opam repository set-url default http://opam.ocaml.org \ - && opam switch 4.05 \ + && opam switch 4.12 \ && echo 'pre-session-commands: [ "sudo" "apk" "add" depexts ]' >> ~/.opam/config \ && opam pin add -n -y -k path learn-ocaml-client . \ && opam install learn-ocaml-client --deps-only diff --git a/Makefile b/Makefile index 09e30c4df..ab00682a7 100644 --- a/Makefile +++ b/Makefile @@ -57,7 +57,7 @@ testrun: build install learn-ocaml build --repo $(REPO) -j1 rm -rf www/css ln -s ../static/css www - learn-ocaml serve + LEARNOCAML_SERVER_NOCACHE=1 learn-ocaml serve docker-images: Dockerfile learn-ocaml.opam @rm -rf docker @@ -95,7 +95,7 @@ travis: # From https://stackoverflow.com/questions/21053657/how-to-run-travis-ci static-binaries: ./scripts/static-build.sh -BINARIES = src/main/learnocaml_client.bc src/main/learnocaml_main.bc src/main/learnocaml_server_main.exe +BINARIES = src/main/learnocaml_client.bc.exe src/main/learnocaml_main.bc.exe src/main/learnocaml_server_main.exe .PHONY: detect-libs detect-libs: @@ -104,6 +104,7 @@ detect-libs: baseid="detect-libs.$$$$"; echo ...; \ $(MAKE) LINKING_MODE=dynamic OCAMLPARAM="_,verbose=1" > $$baseid.log 2>&1; \ for bin in $(BINARIES); do \ + rm -f "_build/default/$$bin"; \ base=$${bin#src/main/}; base=$${base%.*}; \ grep -e "'$$bin'" $$baseid.log > $$baseid.$$base.log; \ printf "%s: " "$$base"; \ diff --git a/docs/tutorials/step-7.md b/docs/tutorials/step-7.md index 93986c0ef..abf8612f4 100644 --- a/docs/tutorials/step-7.md +++ b/docs/tutorials/step-7.md @@ -34,7 +34,7 @@ exception OutOfRange of int For the first graded function, we want to be sure the student function returned both the right `Ok` output and the right exception with its is correct argument. The predefined tester that compares both possible -results with `Pervasives.compare` function is called `test`. This is +results with `Stdlib.compare` function is called `test`. This is obviously the default value of optional argument [~test]. ```ocaml @@ -192,7 +192,7 @@ let p_list l = let t = List.fold_left (fun a x -> a && p x) true l in if t then (* Check that there is at least two different elements *) - let l = List.sort_uniq (Pervasives.compare) l in + let l = List.sort_uniq (Stdlib.compare) l in if List.length l > 1 then true else false else false @@ -202,4 +202,4 @@ let exercise_2 = ~gen:0 ~test:(test_eq_ok (fun x _ -> p_list x)) [10 ; 20] -``` \ No newline at end of file +``` diff --git a/dune b/dune index 1a22f2d2a..cacc11a85 100644 --- a/dune +++ b/dune @@ -7,7 +7,7 @@ ) (env - (release (flags -safe-string -w +a-4-42-44-45-48-3) + (release (flags -safe-string -w +a-4-42-44-45-48-3-58) (ocamlc_flags) (ocamlopt_flags)) ) diff --git a/dune-project b/dune-project index e05768ed6..42ce0db75 100644 --- a/dune-project +++ b/dune-project @@ -1,3 +1,4 @@ -(lang dune 1.7) +(lang dune 2.3) (name learn-ocaml) (version 0.12) +(allow_approximate_merlin) diff --git a/learn-ocaml-client.opam b/learn-ocaml-client.opam index e824aa73e..e32fa2879 100644 --- a/learn-ocaml-client.opam +++ b/learn-ocaml-client.opam @@ -21,24 +21,24 @@ depends: [ "asak" "gg" "vg" - "cohttp" {>= "1.0.0" & < "2.0.0"} - "cohttp-lwt-unix" {>= "1.0.0" & < "2.0.0"} + "cohttp" {>= "2.0.0"} + "cohttp-lwt-unix" {>= "2.0.0"} "ssl" {= "0.5.5"} "digestif" {>= "0.7.1"} - "dune" {>= "1.11.4" & <= "2.0.1"} + "dune" "ezjsonm" "lwt" {>= "4.0.0"} "lwt_ssl" - "ocaml" {= "4.05.0"} + "ocaml" {= "4.12.0"} "ocamlfind" {build} "ocp-indent-nlfork" "ocp-ocamlres" {>= "0.4"} - "ocplib-json-typed" {= "0.6"} + "ocplib-json-typed" {>= "0.7"} "ipaddr" {= "2.8.0" } "cstruct" {>= "3.3.0"} "ppx_tools" - "ppx_sexp_conv" {= "v0.9.0"} - "ppx_fields_conv" {= "v0.9.0"} + "ppx_sexp_conv" + "ppx_fields_conv" ] build: [ ["dune" "build" "@install" "-p" name "-j" jobs] diff --git a/learn-ocaml-client.opam.locked b/learn-ocaml-client.opam.locked new file mode 100644 index 000000000..e6c67f20b --- /dev/null +++ b/learn-ocaml-client.opam.locked @@ -0,0 +1,107 @@ +opam-version: "2.0" +name: "learn-ocaml-client" +version: "0.12" +synopsis: "The learn-ocaml client" +description: """\ +This contains the binaries to interact with the learn-ocaml +platform from the command line.""" +maintainer: "Yann Régis-Gianas" +authors: [ + "Benjamin Canou (OCamlPro)" + "Çağdaş Bozman (OCamlPro)" + "Grégoire Henry (OCamlPro)" + "Louis Gesbert (OCamlPro)" + "Pierrick Couderc (OCamlPro)" +] +license: "MIT" +homepage: "https://github.com/ocaml-sf/learn-ocaml" +bug-reports: "https://github.com/ocaml-sf/learn-ocaml/issues" +depends: [ + "angstrom" {= "0.15.0"} + "asak" {= "0.3"} + "astring" {= "0.8.5"} + "base" {= "v0.14.1"} + "base-bigarray" {= "base"} + "base-bytes" {= "base"} + "base-threads" {= "base"} + "base-unix" {= "base"} + "base64" {= "3.5.0"} + "bigarray-compat" {= "1.0.0"} + "bigstringaf" {= "0.8.0"} + "biniou" {= "1.2.1"} + "cmdliner" {= "1.0.4"} + "cohttp" {= "4.0.0"} + "cohttp-lwt" {= "4.0.0"} + "cohttp-lwt-unix" {= "4.0.0"} + "conduit" {= "1.3.0"} + "conduit-lwt" {= "1.3.0"} + "conduit-lwt-unix" {= "1.3.0"} + "conf-libssl" {= "3"} + "conf-pkg-config" {= "2"} + "conf-which" {= "1"} + "cppo" {= "1.6.7"} + "csexp" {= "1.5.1"} + "cstruct" {= "5.0.0"} + "digestif" {= "1.0.0"} + "dune" {= "2.9.0"} + "dune-configurator" {= "2.9.0"} + "easy-format" {= "1.3.2"} + "eqaf" {= "0.7"} + "ezjsonm" {= "1.1.0"} + "fieldslib" {= "v0.14.0"} + "fmt" {= "0.8.9"} + "gg" {= "0.9.3"} + "hex" {= "1.4.0"} + "ipaddr" {= "2.8.0"} + "jbuilder" {= "1.0+beta20.2"} + "js_of_ocaml" {= "3.9.0"} + "js_of_ocaml-compiler" {= "3.9.1"} + "js_of_ocaml-ppx" {= "3.9.0"} + "jsonm" {= "1.0.1"} + "logs" {= "0.7.0"} + "lwt" {= "5.4.1"} + "lwt_ssl" {= "1.1.3"} + "magic-mime" {= "1.1.3"} + "menhir" {= "20210419"} + "menhirLib" {= "20210419"} + "menhirSdk" {= "20210419"} + "mmap" {= "1.1.0"} + "num" {= "1.4"} + "ocaml" {= "4.12.0"} + "ocaml-compiler-libs" {= "v0.12.3"} + "ocaml-config" {= "2"} + "ocaml-migrate-parsetree" {= "1.8.0"} + "ocaml-options-vanilla" {= "1"} + "ocaml-syntax-shims" {= "1.0.0"} + "ocamlbuild" {= "0.14.0"} + "ocamlfind" {= "1.9.1"} + "ocp-indent-nlfork" {= "1.5.4"} + "ocp-ocamlres" {= "0.4"} + "ocplib-endian" {= "1.1"} + "ocplib-json-typed" {= "0.7.1"} + "omd" {= "1.3.1"} + "parsexp" {= "v0.14.1"} + "pprint" {= "20200410"} + "ppx_derivers" {= "1.2.1"} + "ppx_fields_conv" {= "v0.14.1"} + "ppx_sexp_conv" {= "v0.14.1"} + "ppx_tools" {= "6.3"} + "ppxlib" {= "0.15.0"} + "re" {= "1.9.0"} + "result" {= "1.5"} + "seq" {= "0.2.2"} + "sexplib" {= "v0.14.0"} + "sexplib0" {= "v0.14.0"} + "ssl" {= "0.5.5"} + "stdlib-shims" {= "0.3.0"} + "stringext" {= "1.6.0"} + "topkg" {= "1.0.3"} + "uchar" {= "0.0.2"} + "uri" {= "4.2.0"} + "uri-sexp" {= "4.2.0"} + "uutf" {= "1.0.2"} + "vg" {= "0.9.4"} + "yojson" {= "1.7.0"} +] +build: ["dune" "build" "@install" "-p" name "-j" jobs] +dev-repo: "git+https://github.com/ocaml-sf/learn-ocaml" diff --git a/learn-ocaml.opam b/learn-ocaml.opam index a89a43dea..3eb7defa5 100644 --- a/learn-ocaml.opam +++ b/learn-ocaml.opam @@ -17,15 +17,15 @@ depends: [ "base" {>= "v0.9.4"} "base64" "cmdliner" - "cohttp" {>= "1.0.0" & < "2.0.0"} - "cohttp-lwt" {>= "1.0.0" & < "2.0.0"} - "cohttp-lwt-unix" {>= "1.0.0" & < "2.0.0"} + "cohttp" {>= "2.0.0"} + "cohttp-lwt" {>= "2.0.0"} + "cohttp-lwt-unix" {>= "2.0.0"} "conf-git" "decompress" {= "0.8.1"} "digestif" {>= "0.7.1"} "dune" {>= "1.11.4"} "easy-format" {>= "1.3.0" } - "ipaddr" {= "2.8.0" } + "ipaddr" {>= "2.8.0" } "ezjsonm" "js_of_ocaml" {>= "3.3.0"} "js_of_ocaml-compiler" {>= "3.3.0"} @@ -40,13 +40,14 @@ depends: [ "magic-mime" "markup" "markup-lwt" - "ocaml" {= "4.05.0"} + "ocaml" {= "4.12.0"} "ocamlfind" {build} "ocp-indent-nlfork" - "ocp-ocamlres" {>= "0.4"} - "ocplib-json-typed" {= "0.6"} - "odoc" {build & >= "1.3.0"} - "omd" {<= "1.3.1"} + "ocp-ocamlres" {= "0.4"} + "ocplib-json-typed" {>= "0.6"} + "ocplib-json-typed-browser" {>= "0.6"} + "odoc" {build} + "omd" "pprint" "ppx_cstruct" "ppx_tools" diff --git a/learn-ocaml.opam.locked b/learn-ocaml.opam.locked index ad7b2abf8..40f7a6ef0 100644 --- a/learn-ocaml.opam.locked +++ b/learn-ocaml.opam.locked @@ -14,105 +14,107 @@ homepage: "https://github.com/ocaml-sf/learn-ocaml" bug-reports: "https://github.com/ocaml-sf/learn-ocaml/issues" dev-repo: "git+https://github.com/ocaml-sf/learn-ocaml" depends: [ - "asak" {= "0.2"} - "astring" {= "0.8.4"} - "base" {= "v0.9.4"} + "angstrom" {= "0.15.0"} + "asak" {= "0.3"} + "astring" {= "0.8.5"} + "base" {= "v0.14.1"} "base-bigarray" {= "base"} "base-bytes" {= "base"} - "base-num" {= "base"} "base-threads" {= "base"} "base-unix" {= "base"} - "base64" {= "2.3.0"} + "base64" {= "3.5.0"} "bigarray-compat" {= "1.0.0"} + "bigstringaf" {= "0.8.0"} "biniou" {= "1.2.1"} - "checkseum" {= "0.1.0"} + "checkseum" {= "0.3.1"} "cmdliner" {= "1.0.4"} - "cohttp" {= "1.1.1"} - "cohttp-lwt" {= "1.1.1"} - "cohttp-lwt-unix" {= "1.1.1"} + "cohttp" {= "4.0.0"} + "cohttp-lwt" {= "4.0.0"} + "cohttp-lwt-unix" {= "4.0.0"} "conduit" {= "1.3.0"} "conduit-lwt" {= "1.3.0"} "conduit-lwt-unix" {= "1.3.0"} "conf-git" {= "1.0"} - "conf-libssl" {= "1"} - "conf-m4" {= "1"} - "conf-pkg-config" {= "1.2"} + "conf-libssl" {= "3"} + "conf-pkg-config" {= "2"} "conf-which" {= "1"} - "cppo" {= "1.6.6"} + "cppo" {= "1.6.7"} + "csexp" {= "1.5.1"} "cstruct" {= "5.0.0"} "decompress" {= "0.8.1"} - "digestif" {= "0.8.0-1"} - "dune" {= "2.0.1"} + "digestif" {= "1.0.0"} + "dune" {= "2.9.0"} + "dune-configurator" {= "2.9.0"} "easy-format" {= "1.3.2"} "eqaf" {= "0.7"} "ezjsonm" {= "1.1.0"} - "fieldslib" {= "v0.9.0"} - "fmt" {= "0.8.8"} - "fpath" {= "0.7.2"} + "fmt" {= "0.8.9"} + "fpath" {= "0.7.3"} + "gg" {= "0.9.3"} "hex" {= "1.4.0"} "ipaddr" {= "2.8.0"} "jbuilder" {= "1.0+beta20.2"} - "js_of_ocaml" {= "3.3.0"} - "js_of_ocaml-compiler" {= "3.3.0"} - "js_of_ocaml-lwt" {= "3.3.0"} - "js_of_ocaml-ppx" {= "3.3.0"} - "js_of_ocaml-toplevel" {= "3.3.0"} - "js_of_ocaml-tyxml" {= "3.3.0"} + "js_of_ocaml" {= "3.9.0"} + "js_of_ocaml-compiler" {= "3.9.1"} + "js_of_ocaml-lwt" {= "3.9.0"} + "js_of_ocaml-ppx" {= "3.9.0"} + "js_of_ocaml-toplevel" {= "3.9.0"} + "js_of_ocaml-tyxml" {= "3.9.0"} "jsonm" {= "1.0.1"} - "markup-lwt" {= "0.5.0"} "logs" {= "0.7.0"} - "lwt" {= "4.2.1"} - "lwt_react" {= "1.1.3"} + "lwt" {= "5.4.1"} + "lwt_react" {= "1.1.4"} "lwt_ssl" {= "1.1.3"} - "magic-mime" {= "1.1.2"} + "magic-mime" {= "1.1.3"} "markup" {= "0.8.2"} + "markup-lwt" {= "0.5.0"} + "menhir" {= "20210419"} + "menhirLib" {= "20210419"} + "menhirSdk" {= "20210419"} "mmap" {= "1.1.0"} - "num" {= "0"} - "ocaml" {= "4.05.0"} - "ocaml-compiler-libs" {= "v0.9.0"} - "ocaml-migrate-parsetree" {= "1.7.3"} - "ocaml-secondary-compiler" {= "4.08.1-1"} + "num" {= "1.4"} + "ocaml" {= "4.12.0"} + "ocaml-compiler-libs" {= "v0.12.3"} + "ocaml-config" {= "2"} + "ocaml-migrate-parsetree" {= "1.8.0"} + "ocaml-options-vanilla" {= "1"} + "ocaml-syntax-shims" {= "1.0.0"} "ocamlbuild" {= "0.14.0"} - "ocamlfind" {= "1.8.1"} - "ocamlfind-secondary" {= "1.8.1"} + "ocamlfind" {= "1.9.1"} "ocp-indent-nlfork" {= "1.5.4"} "ocp-ocamlres" {= "0.4"} - "ocplib-json-typed" {= "0.6"} - "odoc" {= "1.5.1"} + "ocplib-endian" {= "1.1"} + "ocplib-json-typed" {= "0.7.1"} + "ocplib-json-typed-browser" {= "0.7.1"} + "odoc" {= "1.5.3"} "omd" {= "1.3.1"} - "optint" {= "0.0.2"} + "optint" {= "0.1.0"} + "parsexp" {= "v0.14.1"} "pprint" {= "20200410"} - "ppx_ast" {= "v0.9.1"} - "ppx_core" {= "v0.9.3"} "ppx_cstruct" {= "5.0.0"} "ppx_derivers" {= "1.2.1"} - "ppx_driver" {= "v0.9.2"} - "ppx_fields_conv" {= "v0.9.0"} - "ppx_metaquot" {= "v0.9.0"} - "ppx_optcomp" {= "v0.9.0"} - "ppx_sexp_conv" {= "v0.9.0"} - "ppx_tools" {= "5.0+4.05.0"} + "ppx_sexp_conv" {= "v0.14.1"} + "ppx_tools" {= "6.3"} "ppx_tools_versioned" {= "5.4.0"} - "ppx_traverse_builtins" {= "v0.9.0"} - "ppx_type_conv" {= "v0.9.1"} + "ppxlib" {= "0.15.0"} "re" {= "1.9.0"} "react" {= "1.2.1"} "reactiveData" {= "0.2.1"} "result" {= "1.5"} - "rresult" {= "0.6.0"} "seq" {= "0.2.2"} - "sexplib" {= "v0.9.3"} + "sexplib" {= "v0.14.0"} + "sexplib0" {= "v0.14.0"} "ssl" {= "0.5.5"} - "stdio" {= "v0.9.1"} - "stdlib-shims" {= "0.1.0"} + "stdlib-shims" {= "0.3.0"} "stringext" {= "1.6.0"} - "topkg" {= "1.0.1"} + "topkg" {= "1.0.3"} "tyxml" {= "4.4.0"} "uchar" {= "0.0.2"} - "uri" {= "1.9.7"} + "uri" {= "4.2.0"} + "uri-sexp" {= "4.2.0"} "uutf" {= "1.0.2"} + "vg" {= "0.9.4"} "yojson" {= "1.7.0"} - "vg" {= "0.9.3"} ] build: [ [make "static"] diff --git a/scripts/static-build.sh b/scripts/static-build.sh index adbddf9a5..f336e7f2e 100755 --- a/scripts/static-build.sh +++ b/scripts/static-build.sh @@ -10,11 +10,11 @@ cd $(dirname "$0")/.. set -o pipefail git ls-files -z | xargs -0 tar c | \ docker run --rm -i \ - ocamlpro/ocaml:4.05 \ + ocamlpro/ocaml:4.12-2021-07-25 \ sh -uexc \ 'tar x >&2 && - sudo apk add openssl-libs-static >&2 && - opam switch create . ocaml-system "dune<2" --deps-only >&2 && + sudo apk add openssl-libs-static bash >&2 && + opam switch create . ocaml-system --deps-only --locked >&2 && opam exec make LINKING_MODE=static >&2 && tar c -hC _build/install/default/bin .' | \ tar vx diff --git a/src/ace-lib/ace_bindings.js b/src/ace-lib/ace_bindings.js index dcdd49d52..eb6368a69 100644 --- a/src/ace-lib/ace_bindings.js +++ b/src/ace-lib/ace_bindings.js @@ -16,6 +16,9 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +//Provides: define_ocaml_mode +//Version: 1.3.3 + var define_ocaml_mode = function (name, helpers) { ace.define(name,["require","exports","module", diff --git a/src/ace-lib/build.ocp b/src/ace-lib/build.ocp deleted file mode 100644 index 3f84bdb5a..000000000 --- a/src/ace-lib/build.ocp +++ /dev/null @@ -1,15 +0,0 @@ -begin library "ace" - link += [ "-linkall" ] - files = [ - "ace_types.mli" - "ace.ml" ( comp = ppx_js ) - "ocaml_mode.ml" - ] - requires = [ - "jsutils" - "js_of_ocaml" - "js_of_ocaml-lwt" - "lwt" - "ocp-indent-nlfork.lib" - ] -end diff --git a/src/ace-lib/dune b/src/ace-lib/dune index 4b42ed2eb..1a117fd56 100644 --- a/src/ace-lib/dune +++ b/src/ace-lib/dune @@ -11,5 +11,7 @@ js_of_ocaml-lwt lwt ocp-indent-nlfork.lib) - (preprocess (pps js_of_ocaml.ppx)) + (preprocess (pps js_of_ocaml-ppx)) + (js_of_ocaml + (javascript_files ace_bindings.js)) ) diff --git a/src/ace-lib/ocaml_mode.ml b/src/ace-lib/ocaml_mode.ml index e1af420cd..1ef2c4948 100644 --- a/src/ace-lib/ocaml_mode.ml +++ b/src/ace-lib/ocaml_mode.ml @@ -6,6 +6,7 @@ * Learn-OCaml is distributed under the terms of the MIT license. See the * included LICENSE file for details. *) +open Js_of_ocaml_lwt open Js_utils open Js_of_ocaml open Lwt.Infix @@ -324,16 +325,18 @@ type loc = Ace.loc = { loc_end: int * int; } -type error = { - locs: loc list; - msg: string; -} - -type warning = { +type msg = { loc: loc; msg: string; } +type error = msg list + +type warning = error (* { + * loc: loc; + * msg: string; + * } *) + type editor = { ace: editor Ace.editor; mutable current_error: error option; @@ -356,8 +359,10 @@ let reset_error editor = let report_error editor ?(set_class = true) err warnings = reset_error editor >>= fun () -> Lwt_js.yield () >|= fun () -> - let add_warning editor { loc; msg } = - Ace.set_mark editor ~loc ~type_:Ace.Warning msg in + let add_warning editor = + List.iter (fun {msg; loc} -> + Ace.set_mark editor ~loc ~type_:Ace.Warning msg) + in editor.current_error <- err; editor.current_warnings <- warnings; match err, warnings with @@ -368,17 +373,13 @@ let report_error editor ?(set_class = true) err warnings = if set_class then Ace.add_class editor.ace "ocaml-check-warn"; List.iter (add_warning editor.ace) warnings - | Some { locs; msg }, warnings -> + | Some msgs, warnings -> if set_class then Ace.add_class editor.ace "ocaml-check-error"; List.iter (add_warning editor.ace) warnings; - match locs with - | [] -> - Ace.set_mark editor.ace ~type_:Ace.Error msg - | locs -> - List.iter - (fun loc -> Ace.set_mark editor.ace ~loc ~type_:Ace.Error msg) - locs + List.iter (fun {msg; loc} -> + Ace.set_mark editor.ace ~loc ~type_:Ace.Error msg) + msgs let report_current_error editor ?set_class () = report_error editor ?set_class editor.current_error editor.current_warnings diff --git a/src/ace-lib/ocaml_mode.mli b/src/ace-lib/ocaml_mode.mli index 231360851..d2d2f78f8 100644 --- a/src/ace-lib/ocaml_mode.mli +++ b/src/ace-lib/ocaml_mode.mli @@ -15,16 +15,16 @@ type loc = Ace.loc = { loc_end: int * int; } -type error = { - locs: loc list; - msg: string; -} - -type warning = { +type msg = { loc: loc; msg: string; } + +type error = msg list + +type warning = error + val create_ocaml_editor: Dom_html.divElement Js.t -> editor val get_editor: editor -> editor Ace.editor diff --git a/src/app/build.ocp b/src/app/build.ocp deleted file mode 100644 index d5dc286b9..000000000 --- a/src/app/build.ocp +++ /dev/null @@ -1,77 +0,0 @@ -begin library "learnocaml-app-common" - comp_requires = "ppx_ocplib_i18n:asm" - files = [ - "learnocaml_local_storage.ml" ( comp = ppx_js ) - "server_caller.ml" ( comp = ppx_js ) - "learnocaml_common.ml" ( comp = [ ppx_js ppx_ocplib_i18n ] ) - ] - requires = [ - "ocplib-json-typed.browser" - "js_of_ocaml" - "js_of_ocaml.ppx" - "js_of_ocaml.tyxml" - "jsutils" - "learnocaml-toplevel" - "learnocaml-repository" - "learnocaml-data" - "learnocaml-api" - "ocplib_i18n" - ] -end - -begin program "learnocaml-main" - comp_requires = "ppx_ocplib_i18n:asm" - requires = [ - "ezjsonm" - "ace" - "learnocaml-repository" - "learnocaml-app-common" - "learnocaml-toplevel" - "js_of_ocaml.ppx" - "ocplib_i18n" - ] - files = [ - "learnocaml_index_main.ml" ( comp = [ ppx_js ppx_ocplib_i18n ]) - ] - build_rules = [ - "%{learnocaml-main_FULL_DST_DIR}%/learnocaml-main.js" ( - build_target = true - sources = %byte_exe( p = "learnocaml-main" ) - commands = [ { - "js_of_ocaml" - "+cstruct/cstruct.js" - "%{ace_FULL_SRC_DIR}%/ace_bindings.js" - %byte_exe( p = "learnocaml-main" ) - } ] - ) - ] -end - -begin program "learnocaml-exercise" - comp_requires = "ppx_ocplib_i18n:asm" - requires = [ - "ezjsonm" - "grading-jsoo" - "ace" - "learnocaml-repository" - "learnocaml-app-common" - "learnocaml-toplevel" - "js_of_ocaml.ppx" - "ocplib_i18n" - ] - files = [ - "learnocaml_exercise_main.ml" ( comp = [ ppx_ocplib_i18n ppx_js ] ) - ] - build_rules = [ - "%{learnocaml-exercise_FULL_DST_DIR}%/learnocaml-exercise.js" ( - build_target = true - sources = %byte_exe( p = "learnocaml-exercise" ) - commands = [ { - "js_of_ocaml" - "+cstruct/cstruct.js" - "%{ace_FULL_SRC_DIR}%/ace_bindings.js" - %byte_exe( p = "learnocaml-exercise" ) - } ] - ) - ] -end diff --git a/src/app/dune b/src/app/dune index e48a6d160..e39e59219 100644 --- a/src/app/dune +++ b/src/app/dune @@ -7,17 +7,17 @@ Server_caller Learnocaml_common) (preprocess - (per_module ((pps js_of_ocaml.ppx) + (per_module ((pps js_of_ocaml-ppx) Learnocaml_config Learnocaml_local_storage Server_caller) - ((pps ppx_ocplib_i18n js_of_ocaml.ppx) + ((pps ppx_ocplib_i18n js_of_ocaml-ppx) Learnocaml_common))) (libraries - ocplib-json-typed.browser + ocplib-json-typed-browser js_of_ocaml - js_of_ocaml.ppx - js_of_ocaml.tyxml + js_of_ocaml-ppx + js_of_ocaml-tyxml jsutils learnocaml_toplevel learnocaml_repository @@ -29,7 +29,7 @@ (executable (name learnocaml_index_main) - (modes byte) + (modes byte js) (flags :standard -warn-error -6-9-27-33-39) (libraries ezjsonm ace @@ -37,19 +37,16 @@ learnocaml_repository learnocaml_app_common learnocaml_toplevel - js_of_ocaml.ppx + js_of_ocaml-ppx ocplib_i18n) (modules Learnocaml_teacher_tab Learnocaml_index_main) - (preprocess (pps ppx_ocplib_i18n js_of_ocaml.ppx)) - (js_of_ocaml - (flags :standard +cstruct/cstruct.js) - (javascript_files ../ace-lib/ace_bindings.js)) + (preprocess (pps ppx_ocplib_i18n js_of_ocaml-ppx)) ) (executable (name learnocaml_exercise_main) - (modes byte) + (modes byte js) (flags :standard -warn-error -9-27-33) (libraries ezjsonm grading_jsoo @@ -58,18 +55,15 @@ learnocaml_repository learnocaml_app_common learnocaml_toplevel - js_of_ocaml.ppx + js_of_ocaml-ppx ocplib_i18n) (modules Learnocaml_exercise_main) - (preprocess (pps ppx_ocplib_i18n js_of_ocaml.ppx)) - (js_of_ocaml - (flags :standard +cstruct/cstruct.js) - (javascript_files ../ace-lib/ace_bindings.js)) + (preprocess (pps ppx_ocplib_i18n js_of_ocaml-ppx)) ) (executable (name learnocaml_playground_main) - (modes byte) + (modes byte js) (flags :standard -warn-error -9-27-33) (libraries ezjsonm ace @@ -77,18 +71,15 @@ learnocaml_repository learnocaml_app_common learnocaml_toplevel - js_of_ocaml.ppx + js_of_ocaml-ppx ocplib_i18n) (modules Learnocaml_playground_main) - (preprocess (pps ppx_ocplib_i18n js_of_ocaml.ppx)) - (js_of_ocaml - (flags :standard +cstruct/cstruct.js) - (javascript_files ../ace-lib/ace_bindings.js)) + (preprocess (pps ppx_ocplib_i18n js_of_ocaml-ppx)) ) (executable (name learnocaml_student_view) - (modes byte) + (modes byte js) (flags :standard -warn-error -9-27-33) (libraries ezjsonm grading_jsoo @@ -96,36 +87,30 @@ learnocaml_repository learnocaml_app_common lwt_react - js_of_ocaml.ppx + js_of_ocaml-ppx ocplib_i18n) (modules Learnocaml_student_view) - (preprocess (pps ppx_ocplib_i18n js_of_ocaml.ppx)) - (js_of_ocaml - (flags :standard +cstruct/cstruct.js) - (javascript_files ../ace-lib/ace_bindings.js)) + (preprocess (pps ppx_ocplib_i18n js_of_ocaml-ppx)) ) (executable (name learnocaml_description_main) - (modes byte) + (modes byte js) (flags :standard -warn-error -9-27-33) (libraries ezjsonm ace learnocaml_repository learnocaml_app_common - js_of_ocaml.ppx + js_of_ocaml-ppx ocplib_i18n) (modules Learnocaml_description_main) - (preprocess (pps ppx_ocplib_i18n js_of_ocaml.ppx)) - (js_of_ocaml - (flags :standard +cstruct/cstruct.js) - (javascript_files ../ace-lib/ace_bindings.js)) + (preprocess (pps ppx_ocplib_i18n js_of_ocaml-ppx)) ) (executable (name learnocaml_partition_view) - (modes byte) + (modes byte js) (flags :standard -warn-error -9-27-33) (libraries asak ezjsonm @@ -134,13 +119,10 @@ learnocaml_repository learnocaml_app_common lwt_react - js_of_ocaml.ppx + js_of_ocaml-ppx ocplib_i18n) (modules Learnocaml_partition_view) - (preprocess (pps ppx_ocplib_i18n js_of_ocaml.ppx)) - (js_of_ocaml - (flags :standard +cstruct/cstruct.js) - (javascript_files ../ace-lib/ace_bindings.js)) + (preprocess (pps ppx_ocplib_i18n js_of_ocaml-ppx)) ) (install diff --git a/src/app/learnocaml_common.ml b/src/app/learnocaml_common.ml index bd9c10aff..110b71c3f 100644 --- a/src/app/learnocaml_common.ml +++ b/src/app/learnocaml_common.ml @@ -7,6 +7,8 @@ * included LICENSE file for details. *) open Js_of_ocaml +open Js_of_ocaml_tyxml +open Js_of_ocaml_lwt open Js_utils open Lwt.Infix open Learnocaml_data @@ -918,20 +920,24 @@ let typecheck top ace editor set_class = let error, warnings = match res with | Toploop_results.Ok ((), warnings) -> None, warnings - | Toploop_results.Error (err, warnings) -> Some err, warnings in - let transl_loc { Toploop_results.loc_start ; loc_end } = - { Ocaml_mode.loc_start ; loc_end } in + | Toploop_results.Error (err, warnings) -> Some err, warnings + in + let lexing_to_licol loc = + Lexing.(loc.pos_lnum, loc.pos_cnum - loc.pos_bol); + in + let transl_loc { Warnings.loc_start ; loc_end ; loc_ghost = _} = + { Ace.loc_start = lexing_to_licol loc_start; + Ace.loc_end = lexing_to_licol loc_end } + in + let transl (err0,errs) = + List.map (fun (loc, msg) -> {Ocaml_mode.msg; loc = transl_loc loc}) + (err0::errs) + in let error = match error with | None -> None - | Some { Toploop_results.locs ; msg ; if_highlight } -> - Some { Ocaml_mode.locs = List.map transl_loc locs ; - msg = (if if_highlight <> "" then if_highlight else msg) } in - let warnings = - List.map - (fun { Toploop_results.locs ; msg ; if_highlight } -> - { Ocaml_mode.loc = transl_loc (List.hd locs) ; - msg = (if if_highlight <> "" then if_highlight else msg) }) - warnings in + | Some err -> Some (transl err) + in + let warnings = List.map (fun warn -> transl warn) warnings in Ocaml_mode.report_error ~set_class editor error warnings >|= fun () -> Ace.focus ace diff --git a/src/app/learnocaml_common.mli b/src/app/learnocaml_common.mli index 275f2c8cf..e63095460 100644 --- a/src/app/learnocaml_common.mli +++ b/src/app/learnocaml_common.mli @@ -7,6 +7,7 @@ * included LICENSE file for details. *) open Js_of_ocaml +open Js_of_ocaml_tyxml open Learnocaml_data val find_div_or_append_to_body : string -> [> Html_types.div ] Tyxml_js.Html.elt @@ -197,7 +198,7 @@ val init_toplevel_pane : unit) -> unit -val run_async_with_log : (unit -> 'a Lwt.t) -> unit +val run_async_with_log : (unit -> unit Lwt.t) -> unit val mk_tab_handlers : string -> string list -> (unit -> unit) * (string -> unit) @@ -206,10 +207,10 @@ module type Editor_info = sig val buttons_container : 'a Tyxml_js.Html5.elt end -module Editor_button (E : Editor_info) : sig +module Editor_button (_ : Editor_info) : sig val cleanup : string -> unit val download : string -> unit - val eval : Learnocaml_toplevel.t -> (string -> 'a) -> unit + val eval : Learnocaml_toplevel.t -> (string -> unit) -> unit val sync : Token.t option Lwt.t -> Learnocaml_data.SMap.key -> unit end @@ -226,7 +227,7 @@ val setup_prelude_pane : 'a Ace.editor -> string -> unit val get_token : ?has_server:bool -> unit -> Learnocaml_data.student Learnocaml_data.token option Lwt.t module Display_exercise :functor - (Q : sig + (_ : sig val exercise_link : ?cl:string list -> string -> diff --git a/src/app/learnocaml_config.ml b/src/app/learnocaml_config.ml index f99afef34..71e22f19e 100644 --- a/src/app/learnocaml_config.ml +++ b/src/app/learnocaml_config.ml @@ -5,6 +5,8 @@ * Learn-OCaml is distributed under the terms of the MIT license. See the * included LICENSE file for details. *) +open Js_of_ocaml + class type learnocaml_config = object method enableTryocaml: bool Js.optdef_prop method enableLessons: bool Js.optdef_prop diff --git a/src/app/learnocaml_config.mli b/src/app/learnocaml_config.mli index ba20ae535..da35ea9ab 100644 --- a/src/app/learnocaml_config.mli +++ b/src/app/learnocaml_config.mli @@ -9,6 +9,8 @@ to the values stored in this file. It is "statically linked" with learnocaml-common.ml. *) +open Js_of_ocaml + class type learnocaml_config = object method enableTryocaml: bool Js.optdef_prop method enableLessons: bool Js.optdef_prop diff --git a/src/app/learnocaml_description_main.ml b/src/app/learnocaml_description_main.ml index 8ee7bcbee..29f53b850 100644 --- a/src/app/learnocaml_description_main.ml +++ b/src/app/learnocaml_description_main.ml @@ -1,4 +1,5 @@ open Js_of_ocaml +open Js_of_ocaml_tyxml open Js_utils open Lwt.Infix open Learnocaml_common diff --git a/src/app/learnocaml_exercise_main.ml b/src/app/learnocaml_exercise_main.ml index db13a77a1..da75905e3 100644 --- a/src/app/learnocaml_exercise_main.ml +++ b/src/app/learnocaml_exercise_main.ml @@ -7,6 +7,8 @@ * included LICENSE file for details. *) open Js_of_ocaml +open Js_of_ocaml_tyxml +open Js_of_ocaml_lwt open Js_utils open Lwt.Infix open Learnocaml_common diff --git a/src/app/learnocaml_index_main.ml b/src/app/learnocaml_index_main.ml index cf67f896c..6d21d8583 100644 --- a/src/app/learnocaml_index_main.ml +++ b/src/app/learnocaml_index_main.ml @@ -7,6 +7,8 @@ * included LICENSE file for details. *) open Js_of_ocaml +open Js_of_ocaml_tyxml +open Js_of_ocaml_lwt open Js_utils open Lwt open Learnocaml_data diff --git a/src/app/learnocaml_partition_view.ml b/src/app/learnocaml_partition_view.ml index 0913afd90..e01e9ce56 100644 --- a/src/app/learnocaml_partition_view.ml +++ b/src/app/learnocaml_partition_view.ml @@ -7,6 +7,7 @@ * included LICENSE file for details. *) open Js_of_ocaml +open Js_of_ocaml_tyxml open Js_utils open Lwt open Learnocaml_data diff --git a/src/app/learnocaml_playground_main.ml b/src/app/learnocaml_playground_main.ml index 19edd7830..d877017b0 100644 --- a/src/app/learnocaml_playground_main.ml +++ b/src/app/learnocaml_playground_main.ml @@ -7,6 +7,7 @@ * included LICENSE file for details. *) open Js_of_ocaml +open Js_of_ocaml_tyxml open Js_utils open Lwt.Infix open Learnocaml_common diff --git a/src/app/learnocaml_student_view.ml b/src/app/learnocaml_student_view.ml index 6b116b628..c7b3d1303 100644 --- a/src/app/learnocaml_student_view.ml +++ b/src/app/learnocaml_student_view.ml @@ -7,6 +7,7 @@ * included LICENSE file for details. *) open Js_of_ocaml +open Js_of_ocaml_tyxml open Js_utils open Lwt open Learnocaml_data diff --git a/src/app/learnocaml_teacher_tab.ml b/src/app/learnocaml_teacher_tab.ml index db47f5eaa..28a7e9ab1 100644 --- a/src/app/learnocaml_teacher_tab.ml +++ b/src/app/learnocaml_teacher_tab.ml @@ -7,6 +7,7 @@ * included LICENSE file for details. *) open Js_of_ocaml +open Js_of_ocaml_tyxml open Js_utils open Lwt open Learnocaml_data @@ -891,11 +892,11 @@ let rec teacher_tab token _select _params () = (if changes = [] then Lwt.return () else retrieve (Learnocaml_api.Set_exercise_status (token, changes))) - >|= fun () -> + >>= fun () -> (if students_changes = [] then Lwt.return () else retrieve (Learnocaml_api.Set_students_list (token, students_changes))) - >|= fun () -> + >>= fun () -> (* Reload the full tab: a bit more costly, but safer & simpler *) teacher_tab token _select _params () >|= Manip.replaceSelf (find_component "learnocaml-main-teacher") diff --git a/src/app/learnocaml_teacher_tab.mli b/src/app/learnocaml_teacher_tab.mli index a373b9021..0d2fbc7c9 100644 --- a/src/app/learnocaml_teacher_tab.mli +++ b/src/app/learnocaml_teacher_tab.mli @@ -6,6 +6,8 @@ * Learn-OCaml is distributed under the terms of the MIT license. See the * included LICENSE file for details. *) +open Js_of_ocaml_tyxml + val teacher_tab: Learnocaml_data.Token.t -> (unit -> 'a Lwt.t) -> 'b -> unit -> [> Html_types.div ] Tyxml_js.Html5.elt Lwt.t diff --git a/src/app/server_caller.ml b/src/app/server_caller.ml index 4b1837588..3631e90df 100644 --- a/src/app/server_caller.ml +++ b/src/app/server_caller.ml @@ -78,11 +78,11 @@ let urlpath p = let request req = let do_req = function | { Learnocaml_api.meth = `GET; path; args } -> - Lwt_request.get ?headers:None ~url:(urlpath path) ~args:args + Lwt_request.get ?headers:None ~url:(urlpath path) ~args:args () | { Learnocaml_api.meth = `POST body; path; args } -> let get_args = match args with [] -> None | a -> Some a in Lwt_request.post ?headers:None ?get_args - ~url:(urlpath path) ~body:(Some body) + ~url:(urlpath path) ~body:(Some body) () in Lwt.catch (fun () -> Api_client.make_request (fun http_request -> diff --git a/src/cmis.ocp b/src/cmis.ocp deleted file mode 100644 index 6792efba8..000000000 --- a/src/cmis.ocp +++ /dev/null @@ -1,29 +0,0 @@ -embedded_cmis = [ - - "%{stdlib_FULL_DST_DIR}%/pervasives.cmi" - "%{stdlib_FULL_DST_DIR}%/array.cmi" - "%{stdlib_FULL_DST_DIR}%/arrayLabels.cmi" - "%{stdlib_FULL_DST_DIR}%/list.cmi" - "%{stdlib_FULL_DST_DIR}%/camlinternalFormatBasics.cmi" - "%{stdlib_FULL_DST_DIR}%/camlinternalFormat.cmi" - "%{stdlib_FULL_DST_DIR}%/printf.cmi" - "%{stdlib_FULL_DST_DIR}%/random.cmi" - "%{stdlib_FULL_DST_DIR}%/string.cmi" - "%{stdlib_FULL_DST_DIR}%/bytes.cmi" - "%{stdlib_FULL_DST_DIR}%/sys.cmi" - "%{stdlib_FULL_DST_DIR}%/format.cmi" - "%{stdlib_FULL_DST_DIR}%/char.cmi" - "%{stdlib_FULL_DST_DIR}%/printexc.cmi" - "%{stdlib_FULL_DST_DIR}%/digest.cmi" - "%{stdlib_FULL_DST_DIR}%/lexing.cmi" - "%{stdlib_FULL_DST_DIR}%/buffer.cmi" - "%{stdlib_FULL_DST_DIR}%/hashtbl.cmi" - "%{stdlib_FULL_DST_DIR}%/set.cmi" - "%{stdlib_FULL_DST_DIR}%/map.cmi" - "%{stdlib_FULL_DST_DIR}%/topdirs.cmi" - "%{stdlib_FULL_DST_DIR}%/int32.cmi" - "%{stdlib_FULL_DST_DIR}%/int64.cmi" - - (* TODO... add the required stdlib... *) - -] diff --git a/src/config.ocp b/src/config.ocp deleted file mode 100644 index b54f96847..000000000 --- a/src/config.ocp +++ /dev/null @@ -1,3 +0,0 @@ -comp += [ "-safe-string" "-w" "A-4-42-44-45-48" ] -link += [ "-w" "A" ] -has_asm = false diff --git a/src/grader/build.ocp b/src/grader/build.ocp deleted file mode 100644 index 160e195f8..000000000 --- a/src/grader/build.ocp +++ /dev/null @@ -1,157 +0,0 @@ -begin library "learnocaml-report" - comp_requires = "ppx_ocplib_i18n:asm" - files = [ - "learnocaml_report.ml" ( comp = ppx_ocplib_i18n ) - ] - requires = [ - "ocplib_i18n" - "ocplib-json-typed" -(* "learnocaml-repository" *) - ] -end - -begin library "testing" - comp_requires = "ppx_metaquot:asm" - link += [ "-linkall" ] - requires = [ - "ty" - "toploop" - "ppx_metaquot" - "ppx_metaquot_lib" - "ocplib-json-typed" - "learnocaml-report" - "learnocaml-repository" - ] - files = [ - "introspection_intf.mli" - "introspection.ml" ( comp += [ "-ppx" %asm_exe( p = "ppx_metaquot") ] ) - "test_lib.ml" ( comp += [ "-ppx" %asm_exe( p = "ppx_metaquot") ] ) - ] -end - -embedded_grading_cmis = [ - - "%{compiler-libs_FULL_DST_DIR}%/longident.cmi" - "%{compiler-libs_FULL_DST_DIR}%/asttypes.cmi" - "%{compiler-libs_FULL_DST_DIR}%/ast_helper.cmi" - "%{compiler-libs_FULL_DST_DIR}%/ast_mapper.cmi" - "%{compiler-libs_FULL_DST_DIR}%/parsetree.cmi" - "%{compiler-libs_FULL_DST_DIR}%/location.cmi" - "%{compiler-libs_FULL_DST_DIR}%/parse.cmi" - "%{ty_FULL_DST_DIR}%/ty.cmi" - "%{testing_FULL_DST_DIR}%/introspection_intf.cmi" - "%{learnocaml-report_FULL_DST_DIR}%/learnocaml_report.cmi" - "%{testing_FULL_DST_DIR}%/test_lib.cmi" - -] - -begin library "embedded_cmis" - build_rules = [ - "embedded_cmis.ml" ( - build_target = true - sources = embedded_cmis - commands = [ { - "ocp-ocamlres" "-format" "ocamlres" embedded_cmis - } ( stdout = "embedded_cmis.ml" ) ] - ) - ] - files = [ - "embedded_cmis.ml" - ] - requires = [ - "ocplib-ocamlres.runtime" - ] -end - -begin library "grading" - comp_requires = [ "ppx_metaquot:asm" "ppx_ocplib_i18n:asm" ] - link += [ "-linkall" ] - requires = [ - "testing" - "ppx_metaquot" - "ocplib-ocamlres.runtime" - "embedded_cmis" - "ocplib_i18n" - "learnocaml-report" - ] - build_rules = [ - "embedded_grading_cmis.ml" ( - build_target = true - sources = embedded_grading_cmis - commands = [ { - "ocp-ocamlres" "-format" "ocamlres" embedded_grading_cmis - } ( stdout = "embedded_grading_cmis.ml" ) ] - ) - ] - files = [ - "embedded_grading_cmis.ml" - "grading.ml" ( comp += [ ppx_ocplib_i18n "-ppx" %asm_exe( p = "ppx_metaquot") ] ) - ] -end - -begin library "grading-cli" - requires = [ - "toploop_unix" - "grading" - "ocplib-ocamlres" - "ezjsonm" - "lwt_utils" - "learnocaml-report" - ] - files = [ - "grading_cli.ml" - "grader_cli.ml" - ] -end - -begin library "grading-jsoo" - requires = [ - "js_of_ocaml" - "js_of_ocaml-lwt" - "js_of_ocaml.syntax" - "ezjsonm" - "ocplib-json-typed.browser" - "learnocaml-repository" - "learnocaml-report" - "js_of_ocaml.ppx" - ] - files = [ - "grader_jsoo_messages.ml" - "grading_jsoo.ml" ( comp = ppx_js ) - ] -end - -begin program "learnocaml-grader-worker" - comp_requires = [ "ppx_ocplib_i18n:asm" ] - requires = [ - "toploop_jsoo" - "grading" - "ezjsonm" - "ocplib-json-typed.browser" - "js_of_ocaml" - "js_of_ocaml.syntax" - "learnocaml-repository" - "learnocaml-report" - "jsutils" - "js_of_ocaml.ppx" - ] - files = [ - "grader_jsoo_messages.ml" - "grader_jsoo_worker.ml" ( comp = [ ppx_ocplib_i18n ppx_js ] ) - ] - build_rules = [ - "%{learnocaml-grader-worker_FULL_DST_DIR}%/learnocaml-grader-worker.js" ( - build_target = true - sources = %byte_exe( p = "learnocaml-grader-worker" ) - commands = [ { - "js_of_ocaml" - "+cstruct/cstruct.js" - "+dynlink.js" - "+toplevel.js" - "--toplevel" - "--nocmis" - %byte_exe( p = "learnocaml-grader-worker" ) - } ] - ) - ] -end diff --git a/src/grader/dune b/src/grader/dune index 587a1ede7..c3d17b9e9 100644 --- a/src/grader/dune +++ b/src/grader/dune @@ -39,8 +39,8 @@ (action (run odoc compile --package learn-ocaml %{deps} -o %{targets})) ) -(alias - (name doc) +(rule + (alias doc) (action (progn (run mkdir -p doc) (run odoc html %{dep:learnocaml_report.odoc} -o %{workspace_root}/_doc/_html) (run odoc html %{dep:test_lib.odoc} -o %{workspace_root}/_doc/_html))) @@ -51,56 +51,79 @@ (rule (targets embedded_cmis.ml) (deps - (:stdlib_cmis - %{ocaml-config:standard_library}/array.cmi - %{ocaml-config:standard_library}/arrayLabels.cmi - %{ocaml-config:standard_library}/buffer.cmi - %{ocaml-config:standard_library}/bytes.cmi - %{ocaml-config:standard_library}/bigarray.cmi - %{ocaml-config:standard_library}/camlinternalFormatBasics.cmi - %{ocaml-config:standard_library}/camlinternalFormat.cmi - %{ocaml-config:standard_library}/camlinternalLazy.cmi - %{ocaml-config:standard_library}/camlinternalMod.cmi - %{ocaml-config:standard_library}/camlinternalOO.cmi - %{ocaml-config:standard_library}/compiler-libs/topdirs.cmi - %{ocaml-config:standard_library}/char.cmi - %{ocaml-config:standard_library}/complex.cmi - %{ocaml-config:standard_library}/digest.cmi - %{ocaml-config:standard_library}/filename.cmi - %{ocaml-config:standard_library}/format.cmi - %{ocaml-config:standard_library}/hashtbl.cmi - %{ocaml-config:standard_library}/int32.cmi - %{ocaml-config:standard_library}/int64.cmi - %{ocaml-config:standard_library}/lazy.cmi - %{ocaml-config:standard_library}/lexing.cmi - %{ocaml-config:standard_library}/list.cmi - %{ocaml-config:standard_library}/map.cmi - %{ocaml-config:standard_library}/marshal.cmi - %{ocaml-config:standard_library}/pervasives.cmi - %{ocaml-config:standard_library}/printexc.cmi - %{ocaml-config:standard_library}/printf.cmi - %{ocaml-config:standard_library}/queue.cmi - %{ocaml-config:standard_library}/random.cmi - %{ocaml-config:standard_library}/scanf.cmi - %{ocaml-config:standard_library}/set.cmi - %{ocaml-config:standard_library}/stack.cmi - %{ocaml-config:standard_library}/string.cmi - %{ocaml-config:standard_library}/sys.cmi - %{ocaml-config:standard_library}/uchar.cmi - %{ocaml-config:standard_library}/weak.cmi) - - (:local_cmis - ../toplevel/.learnocaml_toplevel_pp.objs/byte/learnocaml_toplevel_pp.cmi) - - (:lib_cmis - %{lib:re:re.cmi} - %{lib:gg:gg.cmi} - %{lib:vg:vg.cmi} - %{lib:vg:vgr_svg.cmi})) - (action - (with-stdout-to %{targets} - (run ocp-ocamlres -format ocamlres %{stdlib_cmis} %{local_cmis} %{lib_cmis})) - ) + (:stdlib_cmis + %{ocaml-config:standard_library}/stdlib.cmi + %{ocaml-config:standard_library}/stdlib__arg.cmi + %{ocaml-config:standard_library}/stdlib__array.cmi + %{ocaml-config:standard_library}/stdlib__arrayLabels.cmi + %{ocaml-config:standard_library}/stdlib__bigarray.cmi + %{ocaml-config:standard_library}/stdlib__bool.cmi + %{ocaml-config:standard_library}/stdlib__buffer.cmi + %{ocaml-config:standard_library}/stdlib__bytes.cmi + %{ocaml-config:standard_library}/stdlib__bytesLabels.cmi + %{ocaml-config:standard_library}/stdlib__callback.cmi + %{ocaml-config:standard_library}/stdlib__char.cmi + %{ocaml-config:standard_library}/stdlib__complex.cmi + %{ocaml-config:standard_library}/stdlib__digest.cmi + %{ocaml-config:standard_library}/stdlib__ephemeron.cmi + %{ocaml-config:standard_library}/stdlib__filename.cmi + %{ocaml-config:standard_library}/stdlib__float.cmi + %{ocaml-config:standard_library}/stdlib__format.cmi + %{ocaml-config:standard_library}/stdlib__fun.cmi + %{ocaml-config:standard_library}/stdlib__gc.cmi + %{ocaml-config:standard_library}/stdlib__genlex.cmi + %{ocaml-config:standard_library}/stdlib__hashtbl.cmi + %{ocaml-config:standard_library}/stdlib__int.cmi + %{ocaml-config:standard_library}/stdlib__int32.cmi + %{ocaml-config:standard_library}/stdlib__int64.cmi + %{ocaml-config:standard_library}/stdlib__lazy.cmi + %{ocaml-config:standard_library}/stdlib__lexing.cmi + %{ocaml-config:standard_library}/stdlib__list.cmi + %{ocaml-config:standard_library}/stdlib__listLabels.cmi + %{ocaml-config:standard_library}/stdlib__map.cmi + %{ocaml-config:standard_library}/stdlib__marshal.cmi + %{ocaml-config:standard_library}/stdlib__moreLabels.cmi + %{ocaml-config:standard_library}/stdlib__nativeint.cmi + %{ocaml-config:standard_library}/stdlib__obj.cmi + %{ocaml-config:standard_library}/stdlib__oo.cmi + %{ocaml-config:standard_library}/stdlib__option.cmi + %{ocaml-config:standard_library}/stdlib__parsing.cmi + %{ocaml-config:standard_library}/stdlib__pervasives.cmi + %{ocaml-config:standard_library}/stdlib__printexc.cmi + %{ocaml-config:standard_library}/stdlib__printf.cmi + %{ocaml-config:standard_library}/stdlib__queue.cmi + %{ocaml-config:standard_library}/stdlib__random.cmi + %{ocaml-config:standard_library}/stdlib__result.cmi + %{ocaml-config:standard_library}/stdlib__scanf.cmi + %{ocaml-config:standard_library}/stdlib__seq.cmi + %{ocaml-config:standard_library}/stdlib__set.cmi + %{ocaml-config:standard_library}/stdlib__stack.cmi + %{ocaml-config:standard_library}/stdlib__stdLabels.cmi + %{ocaml-config:standard_library}/stdlib__stream.cmi + %{ocaml-config:standard_library}/stdlib__string.cmi + %{ocaml-config:standard_library}/stdlib__stringLabels.cmi + %{ocaml-config:standard_library}/stdlib__sys.cmi + %{ocaml-config:standard_library}/stdlib__uchar.cmi + %{ocaml-config:standard_library}/stdlib__unit.cmi + %{ocaml-config:standard_library}/stdlib__weak.cmi + %{ocaml-config:standard_library}/camlinternalFormatBasics.cmi + %{ocaml-config:standard_library}/camlinternalFormat.cmi + %{ocaml-config:standard_library}/camlinternalLazy.cmi + %{ocaml-config:standard_library}/camlinternalMod.cmi + %{ocaml-config:standard_library}/camlinternalOO.cmi + %{ocaml-config:standard_library}/bigarray.cmi + %{ocaml-config:standard_library}/std_exit.cmi + %{ocaml-config:standard_library}/topdirs.cmi) + (:local_cmis + ../toplevel/.learnocaml_toplevel_pp.objs/byte/learnocaml_toplevel_pp.cmi) + + (:lib_cmis + %{lib:re:re.cmi} + %{lib:gg:gg.cmi} + %{lib:vg:vg.cmi} + %{lib:vg:vgr_svg.cmi})) + + (action (with-stdout-to %{targets} (run ocp-ocamlres -format ocamlres %{stdlib_cmis} %{local_cmis} %{lib_cmis}))) ) (library @@ -183,36 +206,35 @@ js_of_ocaml-lwt js_of_ocaml-ppx ezjsonm - ocplib-json-typed.browser + jsutils + ocplib-json-typed-browser learnocaml_repository learnocaml_report - js_of_ocaml.ppx grader_jsoo_messages) (modules Grading_jsoo) - (preprocess (pps js_of_ocaml.ppx)) + (preprocess (pps js_of_ocaml-ppx)) ) (executable (name grader_jsoo_worker) - (modes byte) + (modes byte js) (flags :standard -warn-error -9-27) (link_flags :standard -linkall) (libraries toploop_jsoo grading ezjsonm - ocplib-json-typed.browser + ocplib-json-typed-browser js_of_ocaml js_of_ocaml-ppx ocplib_i18n learnocaml_repository learnocaml_report jsutils - js_of_ocaml.ppx grader_jsoo_messages) (modules Grader_jsoo_worker) - (preprocess (pps ppx_ocplib_i18n js_of_ocaml.ppx)) + (preprocess (pps ppx_ocplib_i18n js_of_ocaml-ppx)) (js_of_ocaml (flags :standard --toplevel --nocmis - +cstruct/cstruct.js +dynlink.js +toplevel.js)) + +dynlink.js +toplevel.js)) ) (install diff --git a/src/grader/grader_jsoo_worker.ml b/src/grader/grader_jsoo_worker.ml index cfcbc8379..2ed208d97 100644 --- a/src/grader/grader_jsoo_worker.ml +++ b/src/grader/grader_jsoo_worker.ml @@ -9,20 +9,28 @@ open Js_of_ocaml let get_grade ?callback exo solution = - let path = "/grading_cmis" in - let root = - OCamlRes.Res.merge - Embedded_cmis.root - Embedded_grading_cmis.root in - Sys_js.mount ~path - (fun ~prefix:_ ~path -> - match OCamlRes.Res.find (OCamlRes.Path.of_string path) root with - | cmi -> - Js.Unsafe.set cmi (Js.string "t") 9 ; (* XXX hack *) - Some cmi - | exception Not_found -> None) ; - Config.load_path := [ path ] ; - Toploop_jsoo.initialize () ; + (* the new toplevel uses directory listings to discover .cmis, so the old + approach of using [Sys_js.mount] for subpaths of individual files no longer + works: we need to mount everything explicitely. *) + (* FIXME: copied from learnocaml_toplevel_worker_main.ml *) + let rec rec_mount path = function + | OCamlRes.Res.Dir (name, children) -> + List.iter (rec_mount (name::path)) children + | OCamlRes.Res.File (name, content) -> + let name = "/" ^ String.concat "/" (List.rev (name::path)) in + Js.Unsafe.set content (Js.string "t") 9 ; (* XXX hack *) + Sys_js.create_file ~name ~content + | OCamlRes.Res.Error _ -> () + in + rec_mount [] (OCamlRes.Res.Dir ("worker_cmis", Embedded_cmis.root)); + rec_mount [] (OCamlRes.Res.Dir ("grading_cmis", Embedded_grading_cmis.root)); + (try Toploop_jsoo.initialize ["/worker_cmis"; "/grading_cmis"] with + | Typetexp.Error (loc, env, error) -> + Js_utils.log "FAILED INIT %a at %a" + (Typetexp.report_error env) error + Location.print_loc loc + | e -> + Js_utils.log "FAILED INIT %s" (Printexc.to_string e)); let divert name chan cb = let redirection = Toploop_jsoo.redirect_channel name chan cb in fun () -> Toploop_jsoo.stop_channel_redirection redirection in @@ -40,22 +48,34 @@ let () = let json = Json_repr_browser.Json_encoding.construct from_worker_enc msg in Worker.post_message json in let ans = - let result, stdout, stderr, outcomes = - get_grade ~callback exercise solution in - match result with - | Ok report -> + match get_grade ~callback exercise solution with + | Ok report, stdout, stderr, outcomes -> Answer (report, stdout, stderr, outcomes) - | Error exn -> + | Error exn, stdout, stderr, outcomes -> let msg = match exn with - | Grading.User_code_error { Toploop_results.msg ; _ } -> - [%i"Error in your solution:\n"] ^ msg - | Grading.Internal_error (step, { Toploop_results.msg ; _ }) -> - [%i"Error in the exercise "] ^ step ^ "\n" ^ msg + | Grading.User_code_error err -> + Format.asprintf [%if"Error in your solution:\n%a\n%!"] + Location.print_report (Toploop_results.to_error err) + | Grading.Internal_error (step, err) -> + Format.asprintf [%if"Error in the exercise %s\n%a\n%!"] + step + Location.print_report (Toploop_results.to_error err) | Grading.Invalid_grader -> [%i"Internal error:\nThe grader did not return a report."] | exn -> [%i"Unexpected error:\n"] ^ Printexc.to_string exn in let report = Learnocaml_report.[ Message ([ Code msg ], Failure) ] in - Answer (report, stdout, stderr, outcomes) in + Answer (report, stdout, stderr, outcomes) + | exception exn -> + let bt = Printexc.get_backtrace () in + let open Learnocaml_report in + let report = + section ~title:"Internal error" [ + failure ~message:"The grader crashed"; + message ~message:(Printexc.to_string exn); + info ~message:bt; + ] in + Answer ([report], "", "", "") + in let json = Json_repr_browser.Json_encoding.construct from_worker_enc ans in Worker.post_message json diff --git a/src/grader/grading.ml b/src/grader/grading.ml index dce50a237..216358e98 100644 --- a/src/grader/grading.ml +++ b/src/grader/grading.ml @@ -13,14 +13,14 @@ exception Invalid_grader let string_of_exn = function | Internal_error (msg, error) -> let msg = - Printf.sprintf [%if"Exercise definition error %s:\n%s\n%!"] - msg error.Toploop_ext.msg + Format.asprintf [%if"Exercise definition error %s:\n%a\n%!"] + msg Location.print_report (Toploop_results.to_error error) in Some msg | User_code_error error -> let msg = - Printf.sprintf [%if"Error in user code:\n\n%s\n%!"] - error.Toploop_ext.msg + Format.asprintf [%if"Error in user code:\n\n%a\n%!"] + Location.print_report (Toploop_results.to_error error) in Some msg | _ -> None @@ -28,9 +28,7 @@ let string_of_exn = function let () = Location.register_error_of_exn (fun exn -> match string_of_exn exn with - | Some msg -> - Some {Location.loc = Location.none ; sub = [] ; - msg ; if_highlight = msg } + | Some msg -> Some (Location.error msg) | None -> None) @@ -86,7 +84,7 @@ let get_grade let msg = String.concat "\n" (List.map Buffer.contents [stderr_buffer; stdout_buffer; outcomes_buffer]) - in fail { Toploop_ext.msg ; locs = [] ; if_highlight = msg } + in fail ((Location.none, msg), []) end | Toploop_ext.Error (err, w) -> warn w ; diff --git a/src/grader/grading_cli.ml b/src/grader/grading_cli.ml index 47e0fcf8f..6b3af3cb5 100644 --- a/src/grader/grading_cli.ml +++ b/src/grader/grading_cli.ml @@ -43,7 +43,7 @@ let get_grade ?callback ?timeout ?dirname exo solution = ResDump.output { OCamlResFormats.base_output_dir = cmis_dir } in dump_cmis Embedded_cmis.root ; dump_cmis Embedded_grading_cmis.root ; - Config.load_path := [ cmis_dir ] ; + Load_path.init [ cmis_dir ] ; Toploop_unix.initialize () ; let divert name chan cb = let redirection = Toploop_unix.redirect_channel name chan cb in diff --git a/src/grader/grading_jsoo.ml b/src/grader/grading_jsoo.ml index e2abda7b5..96da91d61 100644 --- a/src/grader/grading_jsoo.ml +++ b/src/grader/grading_jsoo.ml @@ -11,6 +11,7 @@ exception Timeout open Grader_jsoo_messages open Lwt.Infix open Js_of_ocaml +open Js_of_ocaml_lwt let get_grade ?(worker_js_file = "/js/learnocaml-grader-worker.js") @@ -19,9 +20,13 @@ let get_grade exercise = let t, u = Lwt.task () in let worker = Worker.create worker_js_file in - Lwt.on_cancel t (fun () -> worker##terminate) ; + Lwt.on_cancel t (fun () -> + Js_utils.js_warn "Grading worker END"; + worker##terminate) ; let onmessage (ev : Json_repr_browser.Repr.value Worker.messageEvent Js.t) = let json = ev##.data in + Js_utils.js_warn ("msg from grading worker:"); + Js_utils.js_warn json; begin match Json_repr_browser.Json_encoding.destruct from_worker_enc json with | Callback text -> callback text | Answer (report, stdout, stderr, outcomes) -> @@ -31,10 +36,24 @@ let get_grade Js._true in worker##.onmessage := Dom.handler onmessage ; + let onerror (ev : Worker.errorEvent Js.t) = + worker##terminate ; + let msg = + let open Learnocaml_report in + section ~title:"INTERNAL ERROR" [ + failure ~message:"The grader crashed"; + message ~message:(Js.to_string ev##.message); + ] in + Lwt.wakeup u ([msg], "", "", "") ; + Js._true + in + worker##.onerror := Dom.handler onerror ; Lwt.return @@ fun solution -> let req = { exercise ; solution } in let json = Json_repr_browser.Json_encoding.construct to_worker_enc req in + Js_utils.js_warn ("Sending to grading worker: "); + Js_utils.js_warn json; worker##(postMessage json) ; let timer = Lwt_js.sleep timeout >>= fun () -> diff --git a/src/grader/introspection.ml b/src/grader/introspection.ml index 662c06288..9d6011065 100644 --- a/src/grader/introspection.ml +++ b/src/grader/introspection.ml @@ -38,8 +38,9 @@ let insert_in_env (type t) name (ty : t Ty.ty) (value : t) = Toploop.toplevel_env := begin if String.uncapitalize_ascii name = name then Env.add_value - (Ident.create name) + (Ident.create_local name) { Types. + val_uid = Types.Uid.mk ~current_unit:"Learnocaml_introspection"; val_type = ty.Typedtree.ctyp_type; val_kind = Types.Val_reg; val_attributes = []; @@ -50,7 +51,8 @@ let insert_in_env (type t) name (ty : t Ty.ty) (value : t) = match ty.ctyp_desc with | Ttyp_package { pack_type; _ } -> Env.add_module - (Ident.create name) + (Ident.create_local name) + Types.Mp_present pack_type !Toploop.toplevel_env | _ -> invalid_arg "Learnocaml_toplevel_toploop.insert_in_env (2)" @@ -77,7 +79,7 @@ let insert_mod_ast_in_env ~var_name impl_code = init_loc sig_lb (String.uncapitalize_ascii modname ^ ".mli"); let s = Parse.interface sig_lb in Mod.constraint_ (Mod.structure str) (Mty.signature s) in - Ptop_def [ Str.module_ (Mb.mk (Location.mknoloc modname) m) ] in + Ptop_def [ Str.module_ (Mb.mk (Location.mknoloc (Some modname)) m) ] in let phr = Toploop_ext.Ppx.preprocess_phrase @@ parse_mod_string (String.capitalize_ascii var_name) None impl_code in @@ -107,14 +109,19 @@ let treat_lookup_errors fn = match fn () with (Typetexp.Type_mismatch args)) | exception exn -> match Location.error_of_exn exn with - | None -> Incompatible (Format.asprintf "%a@." Toploop.print_untyped_exception (Obj.repr exn)) - | Some { Location.msg; _ } -> Incompatible msg + | None | Some `Already_displayed -> + Incompatible + (Format.asprintf "%a@." + Toploop.print_untyped_exception (Obj.repr exn)) + | Some (`Ok err) -> + Incompatible + (Format.asprintf "%a@." Location.print_report err) let compatible_type nexp ngot = treat_lookup_errors @@ fun () -> - let path_exp = Env.lookup_type nexp !Toploop.toplevel_env in + let path_exp, _ = Env.find_type_by_name nexp !Toploop.toplevel_env in let decl_exp = Env.find_type path_exp !Toploop.toplevel_env in - let path_got = Env.lookup_type ngot !Toploop.toplevel_env in + let path_got, _ = Env.find_type_by_name ngot !Toploop.toplevel_env in let decl_got = Env.find_type path_got !Toploop.toplevel_env in let texp = Ctype.newconstr path_exp (List.map (fun _ -> Ctype.newvar ()) decl_exp.Types.type_params) in let tgot = Ctype.newconstr path_got (List.map (fun _ -> Ctype.newvar ()) decl_got.Types.type_params) in @@ -125,9 +132,9 @@ let get_value lid ty = treat_lookup_errors @@ fun () -> match Ty.obj ty, String.get (Longident.last lid) 0 with | { Parsetree.ptyp_desc = Parsetree.Ptyp_package (n, rews); _ }, 'A'.. 'Z' -> - begin match Env.lookup_module ~load:false lid !Toploop.toplevel_env with + begin match Env.find_module_by_name lid !Toploop.toplevel_env with | exception Not_found -> Absent - | path -> + | path, _ -> let { Types.md_loc; _ } = Env.find_module path !Toploop.toplevel_env in let phrase = let open Ast_helper in @@ -142,8 +149,8 @@ let get_value lid ty = let buf = Buffer.create 300 in let ppf = Format.formatter_of_buffer buf in if Toploop.execute_phrase false ppf phrase then - let fake_path, _ = Env.lookup_value (Longident.Lident "%fake%") !Toploop.toplevel_env in - Present (Obj.obj @@ Toploop.eval_path !Toploop.toplevel_env fake_path) + let fake_path, _ = Env.find_value_by_name (Longident.Lident "%fake%") !Toploop.toplevel_env in + Present (Obj.obj @@ Toploop.eval_value_path !Toploop.toplevel_env fake_path) else let msg = Format.fprintf ppf "@." ; Buffer.contents buf in failwith msg @@ -152,9 +159,9 @@ let get_value lid ty = let { Typedtree.ctyp_type = exp_type; _ } = Typetexp.transl_type_scheme !Toploop.toplevel_env (Ty.obj ty) in let path, { Types.val_type; _ } = - Env.lookup_value lid !Toploop.toplevel_env in + Env.find_value_by_name lid !Toploop.toplevel_env in if Ctype.moregeneral !Toploop.toplevel_env true val_type exp_type then - Present (Obj.obj @@ Toploop.eval_path !Toploop.toplevel_env path) + Present (Obj.obj @@ Toploop.eval_value_path !Toploop.toplevel_env path) else failwith (Format.asprintf "Wrong type %a." Printtyp.type_sch val_type) @@ -232,10 +239,10 @@ let sample_value ty = match Toploop.execute_phrase false ppf phrase with | true -> let path, { Types.val_type; _ } = - Env.lookup_value (Longident.Lident lid) !Toploop.toplevel_env in + Env.find_value_by_name (Longident.Lident lid) !Toploop.toplevel_env in let gty = Types.{ty with desc = Tarrow (Asttypes.Nolabel, Predef.type_unit, ty, Cok) } in if Ctype.moregeneral !Toploop.toplevel_env true val_type gty then - (Obj.obj @@ Toploop.eval_path !Toploop.toplevel_env path) + (Obj.obj @@ Toploop.eval_value_path !Toploop.toplevel_env path) else (failwith "sampler has the wrong type !") | false -> failwith ("sampler could not be defined, " ^ Buffer.contents buf) @@ -253,7 +260,7 @@ let register_callback name ty f = let ref_lid = - Location.mknoloc Longident.(Ldot(Lident "Pervasives", "ref")) + Location.mknoloc Longident.(Ldot(Lident "Stdlib", "ref")) let create_ref name (ty: 'a Ty.ty) (v: 'a) = let ty = Ty.repr @@ Ast_helper.Typ.constr ref_lid [Ty.obj ty] in diff --git a/src/grader/mutation_test.mli b/src/grader/mutation_test.mli index d6e81d044..7b60cf890 100644 --- a/src/grader/mutation_test.mli +++ b/src/grader/mutation_test.mli @@ -109,4 +109,4 @@ module type S = sig val passed_mutation_testing: Learnocaml_report.t -> bool end -module Make (Test_lib: Test_lib.S) : S +module Make (_: Test_lib.S) : S diff --git a/src/grader/test_lib.ml b/src/grader/test_lib.ml index ec82afea6..57f53ee24 100644 --- a/src/grader/test_lib.ml +++ b/src/grader/test_lib.ml @@ -21,7 +21,7 @@ module type S = sig ?on_structure_item: (Parsetree.structure_item -> Learnocaml_report.t) -> ?on_external: (Parsetree.value_description -> Learnocaml_report.t) -> ?on_include: (Parsetree.include_declaration -> Learnocaml_report.t) -> - ?on_open: (Parsetree.open_description -> Learnocaml_report.t) -> + ?on_open: (Parsetree.open_declaration -> Learnocaml_report.t) -> ?on_module_occurence: (string -> Learnocaml_report.t) -> ?on_variable_occurence: (string -> Learnocaml_report.t) -> ?on_function_call: ((Parsetree.expression * (string * Parsetree.expression) list) -> Learnocaml_report.t) -> @@ -468,7 +468,7 @@ module Make ?on_structure_item: (Parsetree.structure_item -> Learnocaml_report.t) -> ?on_external: (Parsetree.value_description -> Learnocaml_report.t) -> ?on_include: (Parsetree.include_declaration -> Learnocaml_report.t) -> - ?on_open: (Parsetree.open_description -> Learnocaml_report.t) -> + ?on_open: (Parsetree.open_declaration -> Learnocaml_report.t) -> ?on_module_occurence: (string -> Learnocaml_report.t) -> ?on_variable_occurence: (string -> Learnocaml_report.t) -> ?on_function_call: ((Parsetree.expression * (string * Parsetree.expression) list) -> Learnocaml_report.t) -> @@ -518,13 +518,10 @@ module Make let expr mapper expr = add @@ on_expression expr ; match expr with - | { pexp_desc = Pexp_open (popen_override, popen_lid, iexpr); _ } -> - let o = { popen_lid ; popen_override ; - popen_loc = Location.none ; - popen_attributes = [] } in + | { pexp_desc = Pexp_open (o, iexpr); _ } -> let before = !modules in add @@ on_open o ; - treat_module popen_lid ; + ignore (mapper.module_expr mapper o.popen_expr) ; variables := [] ; modules := [] (* over approximation *) ; ignore (mapper.expr mapper iexpr) ; @@ -534,7 +531,7 @@ module Make let before = !modules in let variables_before = !variables in ignore (mapper.module_expr mapper mexpr) ; - modules := name :: before ; + Option.iter (fun n -> modules := n :: before) name ; variables := variables_before ; ignore (mapper.expr mapper iexpr) ; modules := before ; @@ -625,12 +622,15 @@ module Make let before = !modules in let variables_before = !variables in ignore (mapper.module_expr mapper pmb_expr) ; - modules := pmb_name.Location.txt :: before ; + Option.iter (fun n -> modules := n :: before) pmb_name.Location.txt ; variables := variables_before ; structure_item | { pstr_desc = Pstr_recmodule mbs; _ } -> let variables_before = !variables in - List.iter (fun { pmb_name; _ } -> modules := pmb_name.Location.txt :: !modules) mbs ; + List.iter (fun { pmb_name; _ } -> + Option.iter (fun n -> modules := n :: !modules) + pmb_name.Location.txt) + mbs ; let before = !modules in List.iter (fun { pmb_expr; _ } -> ignore (mapper.module_expr mapper pmb_expr) ; @@ -639,7 +639,7 @@ module Make structure_item | { pstr_desc = Pstr_open o; _ } as si -> add @@ on_open o ; - treat_module o.popen_lid ; + ignore (mapper.module_expr mapper o.popen_expr) ; ignore (default_mapper.structure_item mapper si) ; variables := [] ; modules := [] (* over approximation *) ; @@ -680,7 +680,7 @@ module Make variables := n.Location.txt :: !variables ; default_mapper.pat mapper p | { ppat_desc = Ppat_unpack n; _ } as p -> - modules := n.Location.txt :: !modules ; + Option.iter (fun txt -> modules := txt :: !modules) n.Location.txt ; default_mapper.pat mapper p | { ppat_desc = Ppat_construct (ident, _); _ } as p -> treat_module_prefixes ident ; @@ -779,7 +779,7 @@ module Make let ast_sanity_check ?(modules = []) ast cb = let modules = (* Some may not even be present, we just want to display a message. *) - [ "Obj" ; "Marshal" ; "Pervasives" ; "Sys" ; + [ "Obj" ; "Marshal" ; "Stdlib" ; "Sys" ; "Test_lib" ; "Introspection" ; "Report" ; "Js" ; "Toploop" ; "Compiler" ; "Unix" ] @ modules in let sanity_report = @@ -832,14 +832,18 @@ module Make let existing_type ?(score = 1) name = let open Learnocaml_report in - try let path = Env.lookup_type Longident.(parse ("Code." ^ name)) !Toploop.toplevel_env in + try + let lid = Longident.parse ("Code." ^ name) in + let path, _ = Env.find_type_by_name lid !Toploop.toplevel_env in let _ = Env.find_type path !Toploop.toplevel_env in true, [ Message ( [ Text "Type" ; Code name ; Text "found" ], Success score ) ] with Not_found -> false, [ Message ( [ Text "type" ; Code name ; Text "not found" ], Failure ) ] let abstract_type ?(allow_private = true) ?(score = 5) name = let open Learnocaml_report in - try let path = Env.lookup_type Longident.(parse ("Code." ^ name)) !Toploop.toplevel_env in + try + let lid = Longident.parse ("Code." ^ name) in + let path, _ = Env.find_type_by_name lid !Toploop.toplevel_env in match Env.find_type path !Toploop.toplevel_env with | { Types. type_kind = Types.Type_abstract ; Types. type_manifest = None; _ } -> true, [ Message ([Text "Type" ; Code name ; Text "is abstract as expected." ], Success score) ] @@ -1789,7 +1793,7 @@ module Make printable_funs := (Obj.repr f, n) :: !printable_funs ; f let () = - let path = Path.Pident (Ident.create "fun_printer") in + let path = Path.Pident (Ident.create_local "fun_printer") in let ty = Typetexp.transl_type_scheme !Toploop.toplevel_env (Ty.obj [%ty: _ -> _ ]) in Toploop.install_printer path ty.Typedtree.ctyp_type fun_printer end diff --git a/src/grader/test_lib.mli b/src/grader/test_lib.mli index 2a8845477..0172bc9db 100644 --- a/src/grader/test_lib.mli +++ b/src/grader/test_lib.mli @@ -79,7 +79,7 @@ module type S = sig ?on_structure_item: (Parsetree.structure_item -> Learnocaml_report.t) -> ?on_external: (Parsetree.value_description -> Learnocaml_report.t) -> ?on_include: (Parsetree.include_declaration -> Learnocaml_report.t) -> - ?on_open: (Parsetree.open_description -> Learnocaml_report.t) -> + ?on_open: (Parsetree.open_declaration -> Learnocaml_report.t) -> ?on_module_occurence: (string -> Learnocaml_report.t) -> ?on_variable_occurence: (string -> Learnocaml_report.t) -> ?on_function_call: ( @@ -267,7 +267,7 @@ module type S = sig val test : 'a tester (** [test_ignore] is a {!S.tester} that compares only the constructor of its - {S.result} inputs. The content is ignored. If the constructors + {!S.result} inputs. The content is ignored. If the constructors match, an empty report is returned. *) val test_ignore : 'a tester @@ -284,7 +284,7 @@ module type S = sig val test_eq_exn : (exn -> exn -> bool) -> 'a tester (** [test_canon canon] builds a {!S.tester} that compares its two - {S.result} inputs after application to [canon] function with + {!S.result} inputs after application to [canon] function with Ocaml structural equality. *) val test_canon : ('a result -> 'a result) -> 'a tester @@ -379,7 +379,7 @@ module type S = sig also made at this time and so mutate during solution execution. They can then be compared with [out.test]. - [out.test] is a {S.tester} which actually builds two reports, + [out.test] is a {!S.tester} which actually builds two reports, one using its optional argument [~test_result] and one that compares the values of the references set previously using [test_ref]. By default [~test_result] is equal to @@ -448,7 +448,7 @@ module type S = sig where each element are generated using [sample]. If [~sorted:true] ([false] by default) the generated list is - sorted (using Pervasives.compare). + sorted (using Stdlib.compare). If [~dups:false] ([true] by default), all elements of generated list are unique.*) @@ -581,7 +581,7 @@ module type S = sig (** {3 Returned report}*) - (** The grading functions for functions return a {report} which + (** The grading functions for functions return a {!report} which actually concatenated 4 reports generated by (in this order): - the tester [~test] @@ -1000,7 +1000,8 @@ module type S = sig (** The various grading functions use numerous common optional argument. Here is a list in alphabetic order of each of them. - {3 ?⁠after} defines a function which is called with the current + {3 ?⁠after} + defines a function which is called with the current tested inputs, the student {!type:result} and the solution {!type:result} and returns a new report which is concatenated to reports built with [~test], [~test_sdtout] and [~test_sdterr]. @@ -1008,13 +1009,15 @@ module type S = sig [~before], [~before_user] or [~before_reference] and build an appropriate report. Default value is [fun _ _ _ -> []]. - {3 ?before} defines a function called right before the application + {3 ?before} + defines a function called right before the application of student function to the current tested inputs. Default value is [fun _ -> ()] For [test_function_] only. - {3 ?before_reference} defines a function called right before the + {3 ?before_reference} + defines a function called right before the application of solution function to the current tested inputs. This function is called {b before} student function evaluation. Default value is [fun _ -> ()]. @@ -1022,7 +1025,8 @@ module type S = sig For [test_function__against] and [test_function__against_solution]. - {3 ?before_user} defines a function called right before the + {3 ?before_user} + defines a function called right before the application of student function to the current tested inputs. This function is called {b after} solution function evaluation. Default value is [fun _ -> ()]. @@ -1030,7 +1034,8 @@ module type S = sig For [test_function__against] and [test_function__against_solution]. - {3 ?gen} Number of automatically generated tested inputs. Inputs + {3 ?gen} + Number of automatically generated tested inputs. Inputs are generated using either sampler defined in the current environment or function defined with [~sampler] optional argument. By default, [gen] is [max 5 (10 - List.length @@ -1041,7 +1046,8 @@ module type S = sig See {{!Sampler.sampler_sec}Sampler module}. - {3 ?sampler} defines the function used to automatically generated + {3 ?sampler} + defines the function used to automatically generated inputs. If unset, the grading function checks if a sampler is defined for each input type in the current environment. Such sampler for a type [some-type] must be named [sample_some-type] @@ -1053,20 +1059,23 @@ module type S = sig See {{!Sampler.sampler_sec}Sampler module}. - {3 ?test} defines the function used to compare the output of + {3 ?test} + defines the function used to compare the output of student function and the output of solution function. Default value is {!Tester.test}. See {{!Tester.tester_sec}predefined testers and tester builders}. - {3 ?test_sdterr} defines the function used to compare the standard + {3 ?test_sdterr} + defines the function used to compare the standard output produced by student function and the one produced by solution function. Default value is {!Tester.io_test_ignore}. See {{!Tester.io_tester_sec}predefined IO testers and IO tester builders}. - {3 ?test_sdtout} defines the function used to compare the standard + {3 ?test_sdtout} + defines the function used to compare the standard error produced by student function and the one produced by solution function. Default value is {!Tester.io_test_ignore}. @@ -1240,7 +1249,7 @@ module type S = sig end module Make : functor - (Params : sig + (_ : sig val results : Learnocaml_report.t option ref val set_progress : string -> unit val timeout : int option diff --git a/src/main/build.ocp b/src/main/build.ocp deleted file mode 100644 index a8a2f267d..000000000 --- a/src/main/build.ocp +++ /dev/null @@ -1,28 +0,0 @@ -begin program "learnocaml" - has_asm = false - files = [ - "learnocaml_main.ml" - ] - requires = [ - "cmdliner" - "learnocaml-process-repository-lib" - "learnocaml-server-lib" - "learnocaml-report" - ] -end - -begin program "learnocaml-client" - has_asm = false - files = [ - "learnocaml_client.ml" - ] - requires = [ - "cmdliner" - "lwt.unix" - "lwt_utils" - "cohttp.lwt" - "grading-cli" - "learnocaml-data" - "learnocaml-api" - ] -end diff --git a/src/main/dune b/src/main/dune index a64c87182..9c2140d2f 100644 --- a/src/main/dune +++ b/src/main/dune @@ -6,13 +6,12 @@ ) (executable - (package learn-ocaml) - (public_name learn-ocaml) +;; (package learn-ocaml) ;; missing support in dune, manually installed below +;; (public_name learn-ocaml) (name learnocaml_main) - (modes byte) - (ocamlc_flags :standard -custom) - (flags (:standard -linkall - (:include linking_main.sexp))) + (modes byte_complete) + (ocamlc_flags -custom) + (flags :standard -linkall -verbose (:include linking_main.sexp)) (modules Learnocaml_main) (libraries cmdliner sha @@ -23,26 +22,34 @@ learnocaml_server_args learnocaml_report) ) +(install + (files (learnocaml_main.bc.exe as learn-ocaml)) + (section bin) + (package learn-ocaml)) (executable - (package learn-ocaml-client) - (public_name learn-ocaml-client) +;; (package learn-ocaml-client) ;; missing support in dune, manually installed below +;; (public_name learn-ocaml-client) (name learnocaml_client) - (modes byte) - (ocamlc_flags :standard -custom) - (flags (:standard -linkall - (:include linking_client.sexp))) + (modes byte_complete) + (ocamlc_flags -custom) + (flags :standard -linkall (:include linking_client.sexp)) (modules Learnocaml_client) (libraries cmdliner sha lwt.unix lwt_utils - cohttp.lwt + cohttp-lwt + cohttp-lwt-unix grading_cli learnocaml_data learnocaml_store learnocaml_api) ) +(install + (files (learnocaml_client.bc.exe as learn-ocaml-client)) + (section bin) + (package learn-ocaml-client)) (executable (package learn-ocaml) @@ -57,7 +64,7 @@ (rule (targets linking_main.sexp) (action (with-stdout-to %{targets} - (run ./linking_flags.sh %{env:LINKING_MODE=dynamic} %{ocaml-config:system} laolao_stubs threads camlrun)))) + (run ./linking_flags.sh %{env:LINKING_MODE=dynamic} %{ocaml-config:system} checkseum_c_stubs threads camlrun)))) (rule (targets linking_client.sexp) (action (with-stdout-to %{targets} @@ -65,4 +72,4 @@ (rule (targets linking_server.sexp) (action (with-stdout-to %{targets} - (run ./linking_flags.sh %{env:LINKING_MODE=dynamic} -- laolao_stubs threadsnat)))) + (run ./linking_flags.sh %{env:LINKING_MODE=dynamic} -- checkseum_c_stubs threadsnat)))) diff --git a/src/main/learnocaml_client.ml b/src/main/learnocaml_client.ml index d4518988c..49c88c284 100644 --- a/src/main/learnocaml_client.ml +++ b/src/main/learnocaml_client.ml @@ -633,7 +633,7 @@ module Init = struct let cmd = Term.( - const (fun go co -> Pervasives.exit (Lwt_main.run (init go co))) + const (fun go co -> Stdlib.exit (Lwt_main.run (init go co))) $ Args_global.term $ Args_create_token.term), Term.info ~man ~doc:"Initialize the configuration file." @@ -719,7 +719,7 @@ module Grade = struct let cmd = Term.( - const (fun go eo -> Pervasives.exit (Lwt_main.run (grade go eo))) + const (fun go eo -> Stdlib.exit (Lwt_main.run (grade go eo))) $ Args_global.term $ Args_exercises.term), Term.info ~man ~doc:"Learn-ocaml grading client." @@ -728,7 +728,7 @@ end let use_global f = Term.( - const (fun o -> Pervasives.exit (Lwt_main.run (f o))) + const (fun o -> Stdlib.exit (Lwt_main.run (f o))) $ Args_global.term) module Print_token = struct @@ -858,7 +858,7 @@ module Fetch = struct let cmd = Term.( - const (fun o l -> Pervasives.exit (Lwt_main.run (fetch o l))) + const (fun o l -> Stdlib.exit (Lwt_main.run (fetch o l))) $ Args_global.term $ Args_fetch.term), Term.info ~man ~exits ~doc:"Fetch the user's solutions." @@ -890,7 +890,7 @@ module Create_token = struct let cmd = Term.( - const (fun go co -> Pervasives.exit (Lwt_main.run (create_tok go co))) + const (fun go co -> Stdlib.exit (Lwt_main.run (create_tok go co))) $ Args_global.term_server $ Args_create_token.term), Term.info ~man ~doc:"Create a token." @@ -920,13 +920,13 @@ module Template = struct let cmd = Term.( - const (fun o id -> Pervasives.exit (Lwt_main.run (template o id))) + const (fun o id -> Stdlib.exit (Lwt_main.run (template o id))) $ Args_global.term $ Args_exercise_id.term), Term.info ~man ~doc:"Get the template of a given exercise." "template" end - + module Exercise_list = struct let doc= "Get a structured json containing a list of the exercises of the server" diff --git a/src/main/linking_flags.sh b/src/main/linking_flags.sh index 514840d74..e17688dae 100755 --- a/src/main/linking_flags.sh +++ b/src/main/linking_flags.sh @@ -43,9 +43,10 @@ case $(uname -s) in Linux) case $(. /etc/os-release && echo $ID) in alpine) - COMMON_LIBS="camlstr base_stubs ssl_threads_stubs ssl crypto cstruct_stubs lwt_unix_stubs bigarray unix c" + COMMON_LIBS="camlstr ssl_threads_stubs ssl crypto cstruct_stubs bigstringaf_stubs lwt_unix_stubs unix c" # `m` and `pthread` are built-in musl echo '(-noautolink' + echo ' -verbose' echo ' -cclib -Wl,-Bstatic' echo ' -cclib -static-libgcc' for l in $EXTRA_LIBS $COMMON_LIBS; do @@ -54,14 +55,15 @@ case $(uname -s) in echo ' -cclib -static)' ;; *) - echo "Error: static linking is only supported in Alpine, to avoids glibc constraints" >&2 + echo "Error: static linking is only supported in Alpine, to avoids glibc constraints (use scripts/static-build.sh to build through an Alpine Docker container)" >&2 exit 3 esac ;; Darwin) - COMMON_LIBS="camlstr base_stubs ssl_threads_stubs /usr/local/opt/openssl/lib/libssl.a /usr/local/opt/openssl/lib/libcrypto.a cstruct_stubs lwt_unix_stubs bigarray unix" + COMMON_LIBS="camlstr ssl_threads_stubs /usr/local/opt/openssl/lib/libssl.a /usr/local/opt/openssl/lib/libcrypto.a cstruct_stubs bigstringaf_stubs lwt_unix_stubs unix" # `m` and `pthread` are built-in in libSystem echo '(-noautolink' + echo ' -verbose' for l in $EXTRA_LIBS $COMMON_LIBS; do if [ "${l%.a}" != "${l}" ]; then echo " -cclib $l" else echo " -cclib -l$l" diff --git a/src/ppx-metaquot/build.ocp b/src/ppx-metaquot/build.ocp deleted file mode 100644 index e8bd575f0..000000000 --- a/src/ppx-metaquot/build.ocp +++ /dev/null @@ -1,52 +0,0 @@ -begin program "genlifter" - files = [ - "genlifter.ml" - ] - requires = [ - "ppx_tools" - "compiler-libs" - ] -end - -begin library "ppx_metaquot_lib" - has_asm = true - build_rules = [ - "ast_lifter.ml" ( - build_target = true - sources = [ %byte_exe( p = "genlifter") ] - commands = [ { - %byte_exe( p = "genlifter") - "-I" "%{compiler-libs_FULL_DST_DIR}%" - "Parsetree.expression" - } ( stdout = "ast_lifter.ml" ) ] - ) - ] - files = [ - "ast_lifter.ml" ( comp += [ "-w" "-17" ] ) - "ppx_metaquot.ml" - ] - requires = [ - "ppx_tools" - "compiler-libs" - ] -end - -begin program "ppx_metaquot" - has_asm = true - has_byte = false - requires = [ - "ppx_metaquot_lib" - ] - files = [ - "ppx_metaquot_main.ml" - ] -end - -begin library "ty" - files = [ - "ty.ml" - ] - requires = [ - "compiler-libs" - ] -end diff --git a/src/ppx-metaquot/fun_ty.mli b/src/ppx-metaquot/fun_ty.mli index 8347fd52a..8d0b26f80 100644 --- a/src/ppx-metaquot/fun_ty.mli +++ b/src/ppx-metaquot/fun_ty.mli @@ -132,7 +132,7 @@ end (** [Make], used in [Test_lib], provides a generic printer and sampler for argument lists of n-ary functions, depending on their type. *) -module Make : functor (M : S) -> sig +module Make : functor (_: S) -> sig val print : (('ar -> 'row) Ty.ty, 'ar -> 'urow, 'ret) fun_ty -> Format.formatter -> ('ar -> 'row, 'ar -> 'urow, 'ret) args -> unit diff --git a/src/ppx-metaquot/genlifter.ml b/src/ppx-metaquot/genlifter.ml index 4c380aa97..9579728db 100644 --- a/src/ppx-metaquot/genlifter.ml +++ b/src/ppx-metaquot/genlifter.ml @@ -48,9 +48,9 @@ module Main : sig end = struct let rec gen ty = if Hashtbl.mem printed ty then () - else let tylid = Longident.parse ty in + else let tylid = Longident.parse ty [@ocaml.warning "-3"] in let td = - try Env.find_type (Env.lookup_type tylid env) env + try snd (Env.find_type_by_name tylid env) with Not_found -> Format.eprintf "** Cannot resolve type %s@." ty; exit 2 @@ -63,8 +63,7 @@ module Main : sig end = struct | Lapply _ -> assert false in Hashtbl.add printed ty (); - let sparams = List.mapi (fun i _ -> Printf.sprintf "f%i" i) td.type_params in - let params = List.map mknoloc sparams in + let params = List.mapi (fun i _ -> mknoloc (Printf.sprintf "f%i" i)) td.type_params in let env = List.map2 (fun s t -> t.id, evar s.txt) params td.type_params in let make_result_t tyargs = Typ.(arrow Asttypes.Nolabel (constr (lid ty) tyargs) (var "res")) in let make_t tyargs = @@ -105,10 +104,17 @@ module Main : sig end = struct pconstr qc p, selfcall "constr" [str ty; tuple[str c; list args]] | Cstr_record (l) -> let l = List.map field l in - pconstr qc [Pat.record (List.map fst l) Closed], - selfcall "constr" [str ty; tuple [str c; - selfcall "record" [str (ty ^ "." ^ c); list (List.map snd l)]]] - in + let keep_head ((lid, pattern), _) = + let txt = Longident.Lident (Longident.last lid.txt) in + ({lid with txt}, pattern) + in + pconstr qc [Pat.record (List.map keep_head l) Closed], + selfcall "constr" + [str ty; + tuple [str c; + list [selfcall "record" + [str ""; list (List.map snd l)]]]] + in concrete (func (List.map case l)) | Type_abstract, Some t -> concrete (tyexpr_fun env t) @@ -191,7 +197,7 @@ module Main : sig end = struct let args = let open Arg in [ - "-I", String (fun s -> Config.load_path := Misc.expand_directory Config.standard_library s :: !Config.load_path), + "-I", String (fun s -> Load_path.add_dir (Misc.expand_directory Config.standard_library s)), " Add to the list of include directories"; ] @@ -199,7 +205,7 @@ module Main : sig end = struct Printf.sprintf "%s [options] \n" Sys.argv.(0) let main () = - Config.load_path := [Config.standard_library]; + Load_path.init [Config.standard_library]; Arg.parse (Arg.align args) gen usage; let meths = !meths in let meths = @@ -215,7 +221,7 @@ module Main : sig end = struct meths in let cl = Cstr.mk (pvar "this") meths in - let params = [Typ.var "res", Invariant] in + let params = [Typ.var "res", (NoVariance, NoInjectivity)] in let cl = Ci.mk ~virt:Virtual ~params (mknoloc "lifter") (Cl.structure cl) in let s = [Str.class_ [cl]] in Format.printf "%a@." Pprintast.structure (simplify.Ast_mapper.structure simplify s) diff --git a/src/ppx-metaquot/ppx_metaquot.ml b/src/ppx-metaquot/ppx_metaquot.ml index 0be96060c..7e26487a8 100644 --- a/src/ppx-metaquot/ppx_metaquot.ml +++ b/src/ppx-metaquot/ppx_metaquot.ml @@ -11,6 +11,8 @@ [%pat? ...] maps to code which creates the pattern represented by ... [%str ...] maps to code which creates the structure represented by ... [%stri ...] maps to code which creates the structure item represented by ... + [%sig: ...] maps to code which creates the signature represented by ... + [%sigi: ...] maps to code which creates the signature item represented by ... [%type: ...] maps to code which creates the core type represented by ... Quoted code can refer to expressions representing AST fragments, @@ -20,11 +22,12 @@ [%t ...] where ... is an expression of type Parsetree.core_type [%p ...] where ... is an expression of type Parsetree.pattern [%%s ...] where ... is an expression of type Parsetree.structure + or Parsetree.signature depending on the context. All locations generated by the meta quotation are by default set - to [Ast_helper.default_loc]. This can be overridden by providing a custom - expression which will be inserted wherever a location is required + to [Ast_helper.default_loc]. This can be overriden by providing a custom + expression which will be inserted whereever a location is required in the generated AST. This expression can be specified globally (for the current structure) as a structure item attribute: @@ -64,7 +67,7 @@ module Main : sig val expander: string list -> Ast_mapper.mapper end = struct let prefix ty s = let open Longident in - match parse ty with + match Longident.parse ty [@ocaml.warning "-3"] with | Ldot(m, _) -> String.concat "." (Longident.flatten m) ^ "." ^ s | _ -> s @@ -104,22 +107,22 @@ module Main : sig val expander: string list -> Ast_mapper.mapper end = struct let get_exp loc = function | PStr [ {pstr_desc=Pstr_eval (e, _); _} ] -> e | _ -> - Format.eprintf "%aExpression expected@." - Location.print_error loc; + let report = Location.error ~loc "Expression expected." in + Location.print_report Format.err_formatter report; exit 2 let get_typ loc = function | PTyp t -> t | _ -> - Format.eprintf "%aType expected@." - Location.print_error loc; + let report = Location.error ~loc "Type expected." in + Location.print_report Format.err_formatter report; exit 2 let get_pat loc = function | PPat (t, None) -> t | _ -> - Format.eprintf "%aPattern expected@." - Location.print_error loc; + let report = Location.error ~loc "Pattern expected." in + Location.print_report Format.err_formatter report; exit 2 let exp_lifter loc map = @@ -149,8 +152,17 @@ module Main : sig val expander: string list -> Ast_mapper.mapper end = struct cons (super # lift_Parsetree_structure_item x)) str (nil ()) + method! lift_Parsetree_signature sign = + List.fold_right + (function + | {psig_desc=Psig_extension(({txt="s";loc}, e), _); _} -> + append (get_exp loc e) + | x -> + cons (super # lift_Parsetree_signature_item x)) + sign (nil ()) + method! lift_Parsetree_core_type = function - | {ptyp_desc=Ptyp_extension({txt="t";loc}, e); _} -> map (get_exp loc e) + | {ptyp_desc=Ptyp_extension({txt="t";loc}, e); _} ->map (get_exp loc e) | x -> super # lift_Parsetree_core_type x end @@ -158,11 +170,20 @@ module Main : sig val expander: string list -> Ast_mapper.mapper end = struct let map = map.Ast_mapper.pat map in object inherit [_] Ast_lifter.lifter as super - inherit pat_builder + inherit pat_builder as builder (* Special support for location and attributes in the generated AST *) method! lift_Location_t _ = Pat.any () method! lift_Parsetree_attributes _ = Pat.any () + method! record n fields = + let fields = + List.map (fun (name, pat) -> + match name with + | "pexp_loc_stack" | "ppat_loc_stack" | "ptyp_loc_stack" -> + name, Pat.any () + | _ -> name, pat) fields + in + builder#record n fields (* Support for antiquotations *) method! lift_Parsetree_expression = function @@ -178,10 +199,10 @@ module Main : sig val expander: string list -> Ast_mapper.mapper end = struct | x -> super # lift_Parsetree_core_type x end - let loc = ref (app (evar "Pervasives.!") [evar "Ast_helper.default_loc"]) + let loc = ref (app (evar "Stdlib.!") [evar "Ast_helper.default_loc"]) let handle_attr = function - | {txt="metaloc";loc=l}, e -> loc := get_exp l e + | {attr_name={txt="metaloc";loc=l}; attr_payload=e; _} -> loc := get_exp l e | _ -> () let with_loc ?(attrs = []) f = @@ -270,6 +291,10 @@ module Main : sig val expander: string list -> Ast_mapper.mapper end = struct (exp_lifter !loc this) # lift_Parsetree_structure e | Pexp_extension({txt="stri";_}, PStr [e]) -> (exp_lifter !loc this) # lift_Parsetree_structure_item e + | Pexp_extension({txt="sig";_}, PSig e) -> + (exp_lifter !loc this) # lift_Parsetree_signature e + | Pexp_extension({txt="sigi";_}, PSig [e]) -> + (exp_lifter !loc this) # lift_Parsetree_signature_item e | Pexp_extension({txt="type";loc=l}, e) -> (exp_lifter !loc this) # lift_Parsetree_core_type (get_typ l e) (* ------ ------ *) @@ -294,6 +319,10 @@ module Main : sig val expander: string list -> Ast_mapper.mapper end = struct (pat_lifter this) # lift_Parsetree_structure e | Ppat_extension({txt="stri";_}, PStr [e]) -> (pat_lifter this) # lift_Parsetree_structure_item e + | Ppat_extension({txt="sig";_}, PSig e) -> + (pat_lifter this) # lift_Parsetree_signature e + | Ppat_extension({txt="sigi";_}, PSig [e]) -> + (pat_lifter this) # lift_Parsetree_signature_item e | Ppat_extension({txt="type";loc=l}, e) -> (pat_lifter this) # lift_Parsetree_core_type (get_typ l e) | _ -> @@ -310,9 +339,19 @@ module Main : sig val expander: string list -> Ast_mapper.mapper end = struct end; super.structure_item this x - in - {super with expr; pat; structure; structure_item} + and signature this l = + with_loc + (fun () -> super.signature this l) + and signature_item this x = + begin match x.psig_desc with + | Psig_attribute x -> handle_attr x + | _ -> () + end; + super.signature_item this x + + in + {super with expr; pat; structure; structure_item; signature; signature_item} end let expander = Main.expander diff --git a/src/ppx-metaquot/ppx_metaquot_main.ml b/src/ppx-metaquot/ppx_metaquot_main.ml index 5d65692bf..62a74f952 100644 --- a/src/ppx-metaquot/ppx_metaquot_main.ml +++ b/src/ppx-metaquot/ppx_metaquot_main.ml @@ -1,3 +1,3 @@ let () = - Migrate_parsetree.Driver.register ~name:"ppx_metaquot" (module Migrate_parsetree.OCaml_405) - (fun _config _cookies -> Ppx_metaquot.expander []) + Migrate_parsetree.Driver.register ~name:"ppx_metaquot" (module Migrate_parsetree.OCaml_412) + (fun _config _cookies -> Ppx_metaquot.Main.expander []) diff --git a/src/ppx-metaquot/ty.ml b/src/ppx-metaquot/ty.ml index d8b85e182..dcbe66328 100644 --- a/src/ppx-metaquot/ty.ml +++ b/src/ppx-metaquot/ty.ml @@ -24,21 +24,25 @@ let domains = function let curry (Ty arg) (Ty ret) = Ty { Parsetree.ptyp_desc = Parsetree.Ptyp_arrow (Asttypes.Nolabel, arg, ret) ; ptyp_loc = Location.none ; + ptyp_loc_stack = []; ptyp_attributes = [] } let pair2 (Ty t1) (Ty t2) = Ty {Parsetree.ptyp_desc = Parsetree.Ptyp_tuple [t1; t2]; ptyp_loc = Location.none; + ptyp_loc_stack = []; ptyp_attributes = []} let pair3 (Ty t1) (Ty t2) (Ty t3) = Ty {Parsetree.ptyp_desc = Parsetree.Ptyp_tuple [t1; t2; t3]; ptyp_loc = Location.none; + ptyp_loc_stack = []; ptyp_attributes = []} let pair4 (Ty t1) (Ty t2) (Ty t3) (Ty t4) = Ty {Parsetree.ptyp_desc = Parsetree.Ptyp_tuple [t1; t2; t3; t4]; ptyp_loc = Location.none; + ptyp_loc_stack = []; ptyp_attributes = []} let lst (Ty ty) = @@ -47,4 +51,5 @@ let lst (Ty ty) = loc = Location.none}, [ty]); ptyp_loc = Location.none; + ptyp_loc_stack = []; ptyp_attributes = []} diff --git a/src/repo/build.ocp b/src/repo/build.ocp deleted file mode 100644 index 6d00625ac..000000000 --- a/src/repo/build.ocp +++ /dev/null @@ -1,52 +0,0 @@ -begin library "learnocaml-repository" - has_asm = false - files = [ - "learnocaml_index.ml" - "learnocaml_exercise.ml" - ] - requires = [ - "ocplib-json-typed" - "xor" - "omd" - "lwt" - "ezjsonm" - ] -end - -begin program "learnocaml-tutorial-reader" - has_asm = false - files = [ - "learnocaml_tutorial_parser.ml" - "learnocaml_tutorial_reader_main.ml" - ] - requires = [ - "ezjsonm" - "str" - "lwt.unix" - "omd" - "markup" - "grading-cli" - "learnocaml-repository" - "learnocaml-data" - ] -end - -begin library "learnocaml-process-repository-lib" - has_asm = false - files = [ - "learnocaml_process_exercise_repository.ml" - "learnocaml_tutorial_parser.ml" - "learnocaml_process_tutorial_repository.ml" - ] - requires = [ - "ezjsonm" - "str" - "lwt.unix" - "lwt_utils" - "omd" - "markup" - "grading-cli" - "learnocaml-repository" - "learnocaml-data" - ] -end diff --git a/src/repo/dune b/src/repo/dune index 3d7e1b651..a82d333a3 100644 --- a/src/repo/dune +++ b/src/repo/dune @@ -18,7 +18,8 @@ learnocaml_data lwt.unix markup - omd) + omd + re) ) (executable diff --git a/src/server/build.ocp b/src/server/build.ocp deleted file mode 100644 index 8f25d0ed3..000000000 --- a/src/server/build.ocp +++ /dev/null @@ -1,28 +0,0 @@ -begin library "learnocaml-server-lib" - files = [ - "learnocaml_server.ml" - ] - requires = [ - "ocplib-json-typed" - "ezjsonm" - "lwt.unix" - "lwt_utils" - "cohttp.lwt" - "magic-mime" - "checkseum.c" - "decompress" - "learnocaml-report" - "learnocaml-data" - "learnocaml-api" - "learnocaml-store" - ] -end - -begin program "learnocaml-server" - files = [ - "learnocaml_server_main.ml" - ] - requires = [ - "learnocaml-server-lib" - ] -end diff --git a/src/server/dune b/src/server/dune index 6925512d6..87cd47f7d 100644 --- a/src/server/dune +++ b/src/server/dune @@ -7,7 +7,7 @@ ezjsonm lwt.unix lwt_utils - cohttp.lwt + cohttp-lwt-unix magic-mime sha checkseum.c diff --git a/src/server/learnocaml_server.ml b/src/server/learnocaml_server.ml index bcb01291d..2b2c00f88 100644 --- a/src/server/learnocaml_server.ml +++ b/src/server/learnocaml_server.ml @@ -86,7 +86,14 @@ type 'a response = type error = (Cohttp.Code.status_code * string) -let caching: type resp. resp Api.request -> caching = function +let disable_cache = + match Sys.getenv_opt "LEARNOCAML_SERVER_NOCACHE" with + | None | Some ("" | "0" | "false") -> false + | Some _ -> true + +let caching: type resp. resp Api.request -> caching = fun resp -> + if disable_cache then Nocache else + match resp with | Api.Version () -> Shortcache (Some ["version"; "server_id"]) | Api.Static ("fonts"::_ | "icons"::_ | "js"::_::_::_ as p) -> Longcache p | Api.Static ("css"::_ | "js"::_ | _ as p) -> Shortcache (Some p) diff --git a/src/state/build.ocp b/src/state/build.ocp deleted file mode 100644 index 029bb573e..000000000 --- a/src/state/build.ocp +++ /dev/null @@ -1,31 +0,0 @@ -begin library "learnocaml-data" - files = [ - "learnocaml_data.ml" - ] - requires = [ - "learnocaml-toplevel-history" - "learnocaml-report" - "learnocaml-repository" - ] -end - -begin library "learnocaml-api" - files = [ - "learnocaml_api.ml" - ] - requires = [ - "ocplib-json-typed" - "ezjsonm" - "learnocaml-data" - ] -end - -begin library "learnocaml-store" - files = [ - "learnocaml_store.ml" - ] - requires = [ - "lwt_utils" - "learnocaml-api" - ] -end diff --git a/src/state/learnocaml_api.mli b/src/state/learnocaml_api.mli index b51db4eb2..2d977d3d0 100644 --- a/src/state/learnocaml_api.mli +++ b/src/state/learnocaml_api.mli @@ -110,7 +110,7 @@ module type REQUEST_HANDLER = sig Learnocaml_data.Server.config -> 'resp request -> 'resp ret end -module Server: functor (Json: JSON_CODEC) (Rh: REQUEST_HANDLER) -> sig +module Server: functor (_: JSON_CODEC) (Rh: REQUEST_HANDLER) -> sig (** Helper to define a server: handles recognition of the incoming request, and encoding of the response. *) @@ -119,7 +119,7 @@ module Server: functor (Json: JSON_CODEC) (Rh: REQUEST_HANDLER) -> sig end -module Client: functor (Json: JSON_CODEC) -> sig +module Client: functor (_: JSON_CODEC) -> sig (** Helper to make a client request: handles encoding of the request and decoding of the response. *) diff --git a/src/state/learnocaml_data.ml b/src/state/learnocaml_data.ml index 39ce6f6d0..e7e009b85 100644 --- a/src/state/learnocaml_data.ml +++ b/src/state/learnocaml_data.ml @@ -260,7 +260,7 @@ module Token = struct module T = struct type nonrec t = t - let compare = Pervasives.compare + let compare = compare end module Set = Set.Make(T) diff --git a/src/state/learnocaml_store.ml b/src/state/learnocaml_store.ml index 06635abcb..084becd2a 100644 --- a/src/state/learnocaml_store.ml +++ b/src/state/learnocaml_store.ml @@ -118,7 +118,7 @@ module Lesson = struct end include (Lesson: module type of struct include Lesson end - with module Index := Index) + with module Index := Lesson.Index) let get id = read_static_file (Learnocaml_index.lesson_path id) enc @@ -137,7 +137,7 @@ module Playground = struct end include (Playground: module type of struct include Playground end - with module Index := Index) + with module Index := Playground.Index) let get id = read_static_file (Learnocaml_index.playground_path id) enc @@ -168,7 +168,7 @@ module Tutorial = struct end include (Tutorial: module type of struct include Tutorial end - with module Index := Index) + with module Index := Tutorial.Index) let get id = read_static_file (Learnocaml_index.tutorial_path id) enc @@ -277,9 +277,9 @@ module Exercise = struct include (Exercise: module type of struct include Exercise end with type id := id - and module Meta := Meta - and module Status := Status - and module Index := Index) + and module Meta := Exercise.Meta + and module Status := Exercise.Status + and module Index := Exercise.Index) let get id = Lwt.catch @@ -550,6 +550,6 @@ module Student = struct let set std = Index.set [std] include (Student: module type of struct include Student end - with module Index := Index) + with module Index := Student.Index) end diff --git a/src/state/learnocaml_store.mli b/src/state/learnocaml_store.mli index f6bbd440b..d3934e24b 100644 --- a/src/state/learnocaml_store.mli +++ b/src/state/learnocaml_store.mli @@ -38,7 +38,7 @@ module Lesson: sig val get: unit -> t Lwt.t end - include module type of struct include Lesson end with module Index := Index + include module type of struct include Lesson end with module Index := Lesson.Index val get: id -> t Lwt.t @@ -51,7 +51,7 @@ module Playground: sig val get: unit -> t Lwt.t end - include module type of struct include Playground end with module Index := Index + include module type of struct include Playground end with module Index := Playground.Index val get: id -> t Lwt.t @@ -68,7 +68,7 @@ module Tutorial: sig val get: unit -> t Lwt.t end - include module type of struct include Tutorial end with module Index := Index + include module type of struct include Tutorial end with module Index := Tutorial.Index val get: id -> t Lwt.t @@ -100,9 +100,9 @@ module Exercise: sig end include module type of struct include Exercise end - with module Meta := Meta - and module Status := Status - and module Index := Index + with module Meta := Exercise.Meta + and module Status := Exercise.Status + and module Index := Exercise.Index val get: id -> t Lwt.t @@ -171,7 +171,7 @@ module Student: sig val set: Student.t list -> unit Lwt.t end - include module type of struct include Student end with module Index := Index + include module type of struct include Student end with module Index := Student.Index val get: student token -> t option Lwt.t diff --git a/src/syntax.ocp b/src/syntax.ocp deleted file mode 100644 index e1c2578b4..000000000 --- a/src/syntax.ocp +++ /dev/null @@ -1,3 +0,0 @@ -ppx_js = [ "-ppx" "%{js_of_ocaml-ppx_FULL_DST_DIR}%/ppx.exe --as-ppx" ] - -ppx_ocplib_i18n = [ "-ppx" %asm_exe( p = "ppx_ocplib_i18n" ) ] diff --git a/src/toplevel/build.ocp b/src/toplevel/build.ocp deleted file mode 100644 index 1596ccba0..000000000 --- a/src/toplevel/build.ocp +++ /dev/null @@ -1,59 +0,0 @@ -begin program "learnocaml-toplevel-worker" - link += [ "-linkall" ] - requires = [ - "jsutils" - "js_of_ocaml" - "js_of_ocaml.ppx" - "toploop_jsoo" - "toploop_results" - "ocplib-ocamlres.runtime" - "embedded_cmis" - ] - files = [ - "learnocaml_toplevel_worker_messages.mli" - "learnocaml_toplevel_worker_main.ml" ( comp = ppx_js ) - ] - build_rules = [ - "%{learnocaml-toplevel-worker_FULL_DST_DIR}%/learnocaml-toplevel-worker.js" ( - build_target = true - sources = %byte_exe( p = "learnocaml-toplevel-worker" ) - commands = [ { - "js_of_ocaml" - "+dynlink.js" - "+toplevel.js" - "--toplevel" - "--nocmis" - %byte_exe( p = "learnocaml-toplevel-worker" ) - } ] - ) - ] -end - -begin library "learnocaml-toplevel-history" - requires = [ - "ocplib-json-typed" - ] - files = [ - "learnocaml_toplevel_history.ml" - ] -end - -begin library "learnocaml-toplevel" - requires = [ - "toploop_results" - "jsutils" - "js_of_ocaml" - "js_of_ocaml.ppx" - "ocp-indent-nlfork.lib" - "ace" - "ocplib-json-typed" - "learnocaml-toplevel-history" - ] - files = [ - "learnocaml_toplevel_worker_messages.mli" - "learnocaml_toplevel_worker_caller.ml" ( comp = ppx_js ) - "learnocaml_toplevel_output.ml" ( comp = ppx_js ) - "learnocaml_toplevel_input.ml" ( comp = ppx_js ) - "learnocaml_toplevel.ml" - ] -end diff --git a/src/toplevel/dune b/src/toplevel/dune index 67b1005a6..337f82112 100644 --- a/src/toplevel/dune +++ b/src/toplevel/dune @@ -10,19 +10,19 @@ (executable (name learnocaml_toplevel_worker_main) - (modes byte) + (modes (byte js)) (flags :standard -w -41 -warn-error -4-42-44-45-48-32-27) (link_flags :standard -linkall) (libraries jsutils js_of_ocaml - js_of_ocaml.ppx + js_of_ocaml-ppx toploop_jsoo toploop_results ocplib-ocamlres.runtime embedded_cmis learnocaml_toplevel_worker_messages) (modules Learnocaml_toplevel_worker_main) - (preprocess (pps js_of_ocaml.ppx)) + (preprocess (pps js_of_ocaml-ppx)) (js_of_ocaml (flags :standard +dynlink.js +toplevel.js --toplevel --nocmis)) ) @@ -50,7 +50,7 @@ (libraries toploop_results jsutils js_of_ocaml - js_of_ocaml.ppx + js_of_ocaml-ppx ocp-indent-nlfork.lib ace ocplib-json-typed @@ -62,7 +62,7 @@ Learnocaml_toplevel_output Learnocaml_toplevel_input Learnocaml_toplevel) - (preprocess (pps ppx_ocplib_i18n js_of_ocaml.ppx)) + (preprocess (pps ppx_ocplib_i18n js_of_ocaml-ppx)) ) diff --git a/src/toplevel/learnocaml_toplevel.ml b/src/toplevel/learnocaml_toplevel.ml index 20fdfa239..1c6e872a1 100644 --- a/src/toplevel/learnocaml_toplevel.ml +++ b/src/toplevel/learnocaml_toplevel.ml @@ -6,6 +6,8 @@ * Learn-OCaml is distributed under the terms of the MIT license. See the * included LICENSE file for details. *) +open Js_of_ocaml_tyxml +open Js_of_ocaml_lwt open Js_utils open Tyxml_js @@ -187,15 +189,20 @@ let execute_phrase top ?timeout content = reset_with_timeout top ~timeout ()); ] >>= fun () -> t >>= fun result -> - let warnings, result = match result with - | Toploop_results.Ok (result, warnings) -> warnings, result + let error, warnings, result = match result with + | Toploop_results.Ok (result, warnings) -> + None, List.map Toploop_results.to_warning warnings, result | Toploop_results.Error (error, warnings) -> - Learnocaml_toplevel_output.output_error ~phrase top.output error ; - warnings, false in + Learnocaml_toplevel_output.output_error ~phrase top.output + (Toploop_results.to_error error) ; + Some (Toploop_results.to_error error), + List.map Toploop_results.to_warning warnings, + false + in List.iter (Learnocaml_toplevel_output.output_warning ~phrase top.output) warnings ; - Lwt.return result + Lwt.return (error, warnings, result) let execute top = Learnocaml_toplevel_input.execute top.input @@ -242,9 +249,9 @@ let load top ?(print_outcome = true) ?timeout ?message content = reset top); ] >>= fun () -> t >>= fun result -> - let warnings, result = match result with - | Toploop_results.Ok (result, warnings) -> warnings, result - | Toploop_results.Error (error, warnings) -> + let warnings, result = match Toploop_results.to_report result with + | Ok (result, warnings) -> warnings, result + | Error (error, warnings) -> Learnocaml_toplevel_output.output_error top.output error ; warnings, false in List.iter @@ -481,8 +488,9 @@ let create Lwt.catch (fun () -> execute_phrase top code) (function - | Lwt.Canceled -> Lwt.return true - | exn -> Lwt.fail exn )) ; + | Lwt.Canceled -> Lwt.return (None, [], true) + | exn -> Lwt.fail exn ) + >>= fun _ -> Lwt.return_unit) ; let first_time = ref true in let after_init top = if !first_time || not oldify then diff --git a/src/toplevel/learnocaml_toplevel.mli b/src/toplevel/learnocaml_toplevel.mli index f2cb5a8f2..e9f5eb887 100644 --- a/src/toplevel/learnocaml_toplevel.mli +++ b/src/toplevel/learnocaml_toplevel.mli @@ -8,7 +8,7 @@ (** An OCaml toplevel whose input and output will be in a given HTML [div]. *) -open Tyxml_js +open Js_of_ocaml_tyxml.Tyxml_js (** An abstract type representing a toplevel instance. *) type t @@ -99,12 +99,12 @@ val make_flood_popup: @param timeout See {!create}. @returns - Returns [Success true] whenever the code was correctly - typechecked and its evaluation did not raise an exception nor - timeouted and [false] otherwise. *) + Returns [errors, warnings, success]. [success] is true whenever the code + was correctly typechecked and its evaluation did not raise an exception + nor timeouted and [false] otherwise. *) val execute_phrase: t -> ?timeout:(t -> unit Lwt.t) -> - string -> bool Lwt.t + string -> (Location.report option * Location.report list * bool) Lwt.t (** Execute a given piece of code without displaying it. @@ -138,12 +138,12 @@ val clear: t -> unit val reset: t -> unit Lwt.t (** Print a message in the toplevel standard output. This is equivalent - to calling [Pervasives.print_string] in the toplevel session. + to calling [Stdlib.print_string] in the toplevel session. Calls {!Learnocaml_toplevel_output.output_stdout}. *) val print_string: t -> string -> unit (** Print a message in the toplevel standard error output. This is - equivalent to calling [Pervasives.prerr_string] in the toplevel + equivalent to calling [Stdlib.prerr_string] in the toplevel session. Calls {!Learnocaml_toplevel_output.output_stderr}. *) val prerr_string: t -> string -> unit diff --git a/src/toplevel/learnocaml_toplevel_input.ml b/src/toplevel/learnocaml_toplevel_input.ml index d27ca008f..b006d9524 100644 --- a/src/toplevel/learnocaml_toplevel_input.ml +++ b/src/toplevel/learnocaml_toplevel_input.ml @@ -7,6 +7,7 @@ * included LICENSE file for details. *) open Js_of_ocaml +open Js_of_ocaml_tyxml let indent_caml s in_lines = let output = { diff --git a/src/toplevel/learnocaml_toplevel_input.mli b/src/toplevel/learnocaml_toplevel_input.mli index 8d3bd3e66..86d8dd1e3 100644 --- a/src/toplevel/learnocaml_toplevel_input.mli +++ b/src/toplevel/learnocaml_toplevel_input.mli @@ -6,6 +6,8 @@ * Learn-OCaml is distributed under the terms of the MIT license. See the * included LICENSE file for details. *) +open Js_of_ocaml_tyxml + (** Toplevel input box. *) (** A toplevel input box handle. *) diff --git a/src/toplevel/learnocaml_toplevel_output.ml b/src/toplevel/learnocaml_toplevel_output.ml index 642300e43..d8c4c2597 100644 --- a/src/toplevel/learnocaml_toplevel_output.ml +++ b/src/toplevel/learnocaml_toplevel_output.ml @@ -7,14 +7,16 @@ * included LICENSE file for details. *) open Js_of_ocaml +open Js_of_ocaml_tyxml +open Js_of_ocaml_lwt type block = | Html of string * [ `Div ] Tyxml_js.Html5.elt | Std of (string * [ `Out | `Err ]) list ref * [ `Pre ] Tyxml_js.Html5.elt | Code of string * pretty list ref * [ `Pre ] Tyxml_js.Html5.elt * Nstream.snapshot option | Answer of string * pretty list ref * [ `Pre ] Tyxml_js.Html5.elt * Nstream.snapshot option - | Error of Toploop_results.error * [ `Pre ] Tyxml_js.Html5.elt - | Warning of int * Toploop_results.warning * [ `Pre ] Tyxml_js.Html5.elt + | Error of Location.report * [ `Pre ] Tyxml_js.Html5.elt + | Warning of int * Location.report * [ `Pre ] Tyxml_js.Html5.elt | Phrase of phrase * block list ref and pretty = @@ -247,13 +249,21 @@ let output_answer ?phrase output answer = (pretty_html pretty) in insert output ?phrase (Answer (answer, ref pretty, pre, snapshot)) pre -open Toploop_results - -let inside (l, c) { loc_start = (sl, sc) ; loc_end = (el, ec) } = +let inside (l, c) loc = + let open Location in + let open Lexing in + let sl = loc.loc_start.pos_lnum in + let sc = loc.loc_start.pos_cnum - loc.loc_start.pos_bol in + let el = loc.loc_end.pos_lnum in + let ec = loc.loc_end.pos_cnum - loc.loc_end.pos_bol in ((l > sl) || (l = sl && c >= sc)) && ((l < el) || (l = el && c < ec)) -let last (l, c) { loc_end = (el, ec) } = +let last (l, c) loc = + let open Location in + let open Lexing in + let el = loc.loc_end.pos_lnum in + let ec = loc.loc_end.pos_cnum - loc.loc_end.pos_bol in l = el && c = ec - 1 let hilight_pretty cls pretty locs lbl = @@ -288,26 +298,33 @@ let hilight_pretty cls pretty locs lbl = fst (hilight_one pretty (1, 0) []) in List.fold_left hilight_one pretty locs +(* Moves [loc] backwards to take into account that [code] has been removed from + the source before it *) let advance_loc code loc = - let rec loop i sl sc el ec = - if i >= String.length code then - { loc_start = (sl, sc) ; loc_end = (el, ec) } - else - let next l c = - (* should work even with ignored '\n's *) - if l > 1 then - (if String.get code i = '\n' then l - 1 else l), c - else - 1, max 0 (c - 1) in - let sl, sc = next sl sc in - let el, ec = next el ec in - loop (i + 1) sl sc el ec in - let { loc_start = (sl, sc) ; loc_end = (el, ec) } = loc in - loop 0 sl sc el ec + let len = String.length code in + let nlcount = + let r = ref 0 in + String.iter (function '\n' -> incr r | _ -> ()) code; + !r + in + let shift pos = + let open Lexing in + { pos with + pos_lnum = max 1 (pos.pos_lnum - nlcount); + pos_cnum = pos.pos_cnum - len; + pos_bol = max 0 (pos.pos_bol - len); + } + in + let open Location in + { loc with + loc_start = shift loc.loc_start; + loc_end = shift loc.loc_end; + } + let hilight cls output u locs lbl = match find_phrase output u with - | None -> assert false + | None -> invalid_arg "Learnocaml_toplevel_output.hilight" | Some l -> let rec loop locs = function | Code (code, pretty, pre, _) :: rest -> @@ -320,36 +337,53 @@ let hilight cls output u locs lbl = loop locs (List.rev !l) let output_error ?phrase output error = - let { Toploop_results.locs ; msg ; if_highlight } = error in + (* TODO: replace by setting Location.report_printer *) let content = [ Tyxml_js.Html5.txt - (match phrase with None -> msg | Some _ -> if_highlight) ] in + (Format.asprintf "%a" Location.print_report error) ] + in let pre = Tyxml_js.Html5.(pre ~a: [ a_class [ "toplevel-error" ] ]) content in + let locs = + List.map (fun m -> m.Location.loc) + (error.Location.main :: error.Location.sub) + in begin match phrase, locs with | None, _ | _, [] -> () | Some u, _ -> hilight "toplevel-hilighted-error" output u locs [] end ; insert output ?phrase (Error (error, pre)) pre +let noloc_report_printer = + let pp_loc = fun _self _report _ppf _loc -> () in + { Location.batch_mode_printer with + Location.pp_main_loc = pp_loc; + Location.pp_submsg_loc = pp_loc } + let output_warning ?phrase output warning = - let { Toploop_results.locs ; msg ; if_highlight } = warning in + Location.report_printer := (fun () -> noloc_report_printer); + let locs = + List.map (fun m -> m.Location.loc) + (warning.Location.main :: warning.Location.sub) + in match phrase, locs with | None, _ | _, [] -> + let msg = Format.asprintf "%a" Location.print_report warning in let pre = Tyxml_js.Html5.(pre ~a: [ a_class [ "toplevel-warning" ] ] [ txt msg ]) in insert output ?phrase (Warning (0, warning, pre)) pre | Some phrase, _ -> phrase.warnings <- phrase.warnings + 1 ; + let msg = Format.asprintf "%a" Location.print_report warning in hilight "toplevel-hilighted-warning" output phrase locs [ Ref phrase.warnings ] ; let pre = Tyxml_js.Html5.(pre ~a: [ a_class [ "toplevel-warning" ] ] [ span ~a: [ a_class [ "ref" ] ] [ txt (string_of_int phrase.warnings) ] ; - txt ":" ; - txt if_highlight ]) in + txt " " ; + txt msg ]) in insert output ~phrase (Warning (phrase.warnings, warning, pre)) pre let clear output = diff --git a/src/toplevel/learnocaml_toplevel_output.mli b/src/toplevel/learnocaml_toplevel_output.mli index e30d7bff7..7145c7dfa 100644 --- a/src/toplevel/learnocaml_toplevel_output.mli +++ b/src/toplevel/learnocaml_toplevel_output.mli @@ -6,6 +6,8 @@ * Learn-OCaml is distributed under the terms of the MIT license. See the * included LICENSE file for details. *) +open Js_of_ocaml_tyxml + (** Toplevel output console. *) (** A toplevel output console handle. *) @@ -93,11 +95,11 @@ val output_answer : ?phrase: phrase -> output -> string -> unit (** Output an error in a [pre] element with class [toplevel-error]. A [span] with class [ref] is used for location labels. *) -val output_error : ?phrase: phrase -> output -> Toploop_results.error -> unit +val output_error : ?phrase: phrase -> output -> Location.report -> unit (** Output a warning in a [pre] element with class [toplevel-warning]. A [span] with class [ref] is used for location labels. *) -val output_warning : ?phrase: phrase -> output -> Toploop_results.warning -> unit +val output_warning : ?phrase: phrase -> output -> Location.report -> unit (** Format OCaml code in the style of {!output_code}. *) val format_ocaml_code : string -> [> `Span | `PCDATA ] Tyxml_js.Html5.elt list diff --git a/src/toplevel/learnocaml_toplevel_worker_caller.ml b/src/toplevel/learnocaml_toplevel_worker_caller.ml index a39e7d82a..c33554edd 100644 --- a/src/toplevel/learnocaml_toplevel_worker_caller.ml +++ b/src/toplevel/learnocaml_toplevel_worker_caller.ml @@ -35,7 +35,7 @@ let wrap pp = module IntMap = Map.Make(struct type t = int - let compare (x:int) (y:int) = Pervasives.compare x y + let compare (x:int) (y:int) = compare x y end) let map_option f o = match o with | None -> None | Some o -> Some (f o) let iter_option f o = match o with | None -> () | Some o -> f o @@ -232,7 +232,7 @@ let reset worker ?(timeout = fun () -> never_ending) () = worker.after_init worker | `Reset Toploop_results.Error (err, _) -> Lwt.cancel timeout; - worker.pp_stderr err.Toploop_results.msg; + worker.pp_stderr (Format.asprintf "%a" Location.print_report (Toploop_results.to_error err)); worker.reset_worker worker | `Timeout -> (* Not canceling the Reset thread, but manually resetting. *) diff --git a/src/toplevel/learnocaml_toplevel_worker_main.ml b/src/toplevel/learnocaml_toplevel_worker_main.ml index 03d0eeacc..50497ce3b 100644 --- a/src/toplevel/learnocaml_toplevel_worker_main.ml +++ b/src/toplevel/learnocaml_toplevel_worker_main.ml @@ -35,7 +35,7 @@ let unwrap_result = module IntMap = Map.Make(struct type t = int - let compare (x:int) (y:int) = Pervasives.compare x y + let compare (x:int) (y:int) = compare x y end) (* Limit the frequency of sent messages to one per ms, using an active @@ -54,12 +54,14 @@ module IntMap = Map.Make(struct does a big computation just after a bufferized write. And it would still need some kind of active waiting to limit throughput. All in all this spinwait is not that ugly. *) -let last = ref 0. -let rec wait () = - let now = Sys.time () (* let's hope this yields a bit *) in - if now -. !last > 0.001 then - last := now - else wait () +let wait = + let last = ref 0. in + let rec aux () = + let now = Sys.time () (* let's hope this yields a bit *) in + if now -. !last > 0.001 then last := now + else aux () + in + aux let post_message (m: toploop_msg) = wait () ; @@ -194,12 +196,14 @@ let handler : type a. a host_msg -> a return Lwt.t = function Ast_helper.(Typ.constr (Location.mknoloc (Longident.Lident "unit")) []) in { Parsetree.ptyp_desc = Parsetree.Ptyp_arrow (Asttypes.Nolabel, arg, ret) ; ptyp_loc = Location.none ; - ptyp_attributes = [] } in + ptyp_attributes = []; + ptyp_loc_stack = [] } in Typetexp.transl_type_scheme !Toploop.toplevel_env ast in Toploop.toplevel_env := Env.add_value - (Ident.create name) + (Ident.create_local name) { Types. + val_uid = Types.Uid.mk ~current_unit:"Learnocaml_callback"; val_type = ty.Typedtree.ctyp_type; val_kind = Types.Val_reg; val_attributes = []; @@ -239,16 +243,26 @@ let () = post_message (ReturnError (id, res, w)); Lwt.return_unit in - let path = "/worker_cmis" in - Sys_js.mount ~path - (fun ~prefix:_ ~path -> - match OCamlRes.Res.find (OCamlRes.Path.of_string path) Embedded_cmis.root with - | cmi -> - Js.Unsafe.set cmi (Js.string "t") 9 ; (* XXX hack *) - Some cmi - | exception Not_found -> None) ; - Config.load_path := [ path ] ; - Toploop_jsoo.initialize (); + (* the new toplevel uses directory listings to discover .cmis, so the old + approach of using [Sys_js.mount] for subpaths of individual files no longer + works: we need to mount everything explicitely. *) + let rec rec_mount path = function + | OCamlRes.Res.Dir (name, children) -> + List.iter (rec_mount (name::path)) children + | OCamlRes.Res.File (name, content) -> + let name = "/" ^ String.concat "/" (List.rev (name::path)) in + Js.Unsafe.set content (Js.string "t") 9 ; (* XXX hack *) + Sys_js.create_file ~name ~content + | OCamlRes.Res.Error _ -> () + in + rec_mount [] (OCamlRes.Res.Dir ("worker_cmis", Embedded_cmis.root)); + (try Toploop_jsoo.initialize ["/worker_cmis"] with + | Typetexp.Error (loc, env, error) -> + Js_utils.log "FAILED INIT %a at %a" + (Typetexp.report_error env) error + Location.print_loc loc + | e -> + Js_utils.log "FAILED INIT %s" (Printexc.to_string e)); Hashtbl.add Toploop.directive_table "debug_worker" (Toploop.Directive_bool (fun b -> debug := b)); diff --git a/src/toploop/build.ocp b/src/toploop/build.ocp deleted file mode 100644 index 4f815acef..000000000 --- a/src/toploop/build.ocp +++ /dev/null @@ -1,35 +0,0 @@ -begin library "toploop_results" - files = [ - "toploop_results.ml" - ] -end - -begin library "toploop" - requires = [ - "compiler-libs.toplevel" - "toploop_results" - ] - files = [ - "toploop_ext.ml" - ] -end - -begin library "toploop_jsoo" - requires = [ - "js_of_ocaml.compiler" - "toploop" - ] - files = [ - "toploop_jsoo.ml" ( comp = ppx_js ) - ] -end - -begin library "toploop_unix" - requires = [ - "lwt.unix" - "toploop" - ] - files = [ - "toploop_unix.ml" - ] -end diff --git a/src/toploop/dune b/src/toploop/dune index f05c7096a..a6ff55a40 100644 --- a/src/toploop/dune +++ b/src/toploop/dune @@ -2,6 +2,7 @@ (name toploop_results) (wrapped false) (modules Toploop_results) + (libraries compiler-libs.toplevel) ) (library @@ -18,9 +19,9 @@ (wrapped false) (modes byte) (flags :standard -warn-error A-4-42-44-45-48-9-58) - (libraries js_of_ocaml.compiler toploop) + (libraries js_of_ocaml-compiler toploop) (modules Toploop_jsoo) - (preprocess (pps js_of_ocaml.ppx)) + (preprocess (pps js_of_ocaml-ppx)) ) (library diff --git a/src/toploop/toploop_ext.ml b/src/toploop/toploop_ext.ml index f8c2084ab..3d318ca5e 100644 --- a/src/toploop/toploop_ext.ml +++ b/src/toploop/toploop_ext.ml @@ -6,22 +6,7 @@ * Learn-OCaml is distributed under the terms of the MIT license. See the * included LICENSE file for details. *) -type 'a toplevel_result = 'a Toploop_results.toplevel_result = - (* ('a * warning list, error * warning list) result = *) - | Ok of 'a * warning list - | Error of error * warning list - -and error = Toploop_results.error = - { msg: string; - locs: loc list; - if_highlight: string; } - -and warning = error - -and loc = Toploop_results.loc = { - loc_start: int * int; - loc_end: int * int; -} +include Toploop_results module Ppx = struct @@ -59,77 +44,34 @@ end let warnings = ref [] -let convert_loc loc = - let _file1,line1,col1 = Location.get_pos_info (loc.Location.loc_start) in - let _file2,line2,col2 = Location.get_pos_info (loc.Location.loc_end) in - { loc_start = (line1, col1) ; loc_end = (line2, col2) } - let () = - Location.warning_printer := - (fun loc _fmt w -> - if Warnings.is_active w then begin - let buf = Buffer.create 503 in - let ppf = Format.formatter_of_buffer buf in - Location.print ppf loc; - Format.fprintf ppf "Warning %a@." Warnings.print w; - let msg = Buffer.contents buf in - Buffer.reset buf; - Format.fprintf ppf "Warning %a@." Warnings.print w; - let if_highlight = Buffer.contents buf in - let loc = convert_loc loc in - warnings := { msg; locs = [loc]; if_highlight } :: !warnings - end) + Location.warning_reporter := + (fun loc w -> + match Warnings.report w with + | `Inactive -> None + | `Active { Warnings.id = _; message; is_error = _; sub_locs } -> + let r = (loc, message), sub_locs in + warnings := r :: !warnings; + None) let return_success (e: 'a) : 'a toplevel_result = Ok (e, !warnings) let return_error e : 'a toplevel_result = Error (e, !warnings) -(* let return_unit_success = return_success () *) (** Error handling *) -let dummy_ppf = Format.make_formatter (fun _ _ _ -> ()) (fun () -> ()) - -let rec report_error_rec hg_ppf ppf {Location.loc; msg; sub; if_highlight} = - Location.print ppf loc; - Format.pp_print_string ppf msg; - let hg_ppf = - if if_highlight <> "" then - (Format.pp_print_string hg_ppf if_highlight; dummy_ppf) - else - (Format.pp_print_string hg_ppf msg; hg_ppf) in - let locs = - List.concat @@ - List.map - (fun err -> - Format.pp_force_newline ppf (); - Format.pp_open_box ppf 2; - let locs = report_error_rec hg_ppf ppf err in - Format.pp_close_box ppf (); - locs) - sub in - convert_loc loc :: locs - -let report_error err = - let buf = Buffer.create 503 in - let ppf = Format.formatter_of_buffer buf in - let hg_buf = Buffer.create 503 in - let hg_ppf = Format.formatter_of_buffer hg_buf in - let locs = report_error_rec hg_ppf ppf err in - Format.pp_print_flush ppf (); - Format.pp_print_flush hg_ppf (); - let msg = Buffer.contents buf in - let if_highlight = Buffer.contents hg_buf in - { msg; locs; if_highlight; } let error_of_exn exn = match Location.error_of_exn exn with - | None -> + | None | Some `Already_displayed -> let msg = match exn with | Failure msg -> msg | exn -> Printexc.to_string exn in - { msg; locs = []; if_highlight = msg } - | Some error -> report_error error + let main = { Location.txt = (fun fmt -> Format.pp_print_text fmt msg); + loc = Location.none } in + { Location.main; sub = []; kind = Location.Report_error } + | Some (`Ok report) -> report -let return_exn exn = return_error (error_of_exn exn) +let return_exn exn = return_error (of_report (error_of_exn exn)) (** Execution helpers *) @@ -199,7 +141,7 @@ let execute ?ppf_code ?(print_outcome = true) ~ppf_answer code = return_success true | exn -> flush_all (); - return_error (error_of_exn exn) + return_exn exn let use_string ?(filename = "//toplevel//") ?(print_outcome = true) ~ppf_answer code = @@ -223,7 +165,7 @@ let use_string return_success false | exn -> flush_all (); - return_error (error_of_exn exn) + return_exn exn let parse_mod_string ?filename modname sig_code impl_code = let open Parsetree in @@ -243,7 +185,7 @@ let parse_mod_string ?filename modname sig_code impl_code = init_loc sig_lb (String.uncapitalize_ascii modname ^ ".mli"); let s = Parse.interface sig_lb in Mod.constraint_ (Mod.structure str) (Mty.signature s) in - Ptop_def [ Str.module_ (Mb.mk (Location.mknoloc modname) m) ] + Ptop_def [ Str.module_ (Mb.mk (Location.mknoloc (Some modname)) m) ] let use_mod_string ?filename @@ -264,15 +206,15 @@ let use_mod_string return_success res with exn -> flush_all (); - return_error (error_of_exn exn) + return_exn exn (* Extracted from the "execute" function in "ocaml/toplevel/toploop.ml" *) let check_phrase env = function | Parsetree.Ptop_def sstr -> Typecore.reset_delayed_checks (); - let (str, sg, newenv) = Typemod.type_toplevel_phrase env sstr in - let sg' = Typemod.simplify_signature sg in - ignore (Includemod.signatures env sg sg'); + let (str, sg, sn, newenv) = Typemod.type_toplevel_phrase env sstr in + let sg' = Typemod.Signature_names.simplify newenv sn sg in + ignore (Includemod.signatures env ~mark:Includemod.Mark_positive sg sg'); Typecore.force_delayed_checks (); let _lam = Translmod.transl_toplevel_definition str in Warnings.check_fatal (); diff --git a/src/toploop/toploop_ext.mli b/src/toploop/toploop_ext.mli index c6903d57b..9dc185353 100644 --- a/src/toploop/toploop_ext.mli +++ b/src/toploop/toploop_ext.mli @@ -6,22 +6,7 @@ * Learn-OCaml is distributed under the terms of the MIT license. See the * included LICENSE file for details. *) -type 'a toplevel_result = 'a Toploop_results.toplevel_result = - (* ('a * warning list, error * warning list) result = *) - | Ok of 'a * warning list - | Error of error * warning list - -and error = Toploop_results.error = - { msg: string; - locs: loc list; - if_highlight: string; } - -and warning = error - -and loc = Toploop_results.loc = { - loc_start: int * int; - loc_end: int * int; -} +include module type of Toploop_results (** Parse and typecheck a given source code. diff --git a/src/toploop/toploop_jsoo.ml b/src/toploop/toploop_jsoo.ml index 497bf39a1..e299a48f7 100644 --- a/src/toploop/toploop_jsoo.ml +++ b/src/toploop/toploop_jsoo.ml @@ -6,8 +6,8 @@ * Learn-OCaml is distributed under the terms of the MIT license. See the * included LICENSE file for details. *) -open Js_of_ocaml_compiler open Js_of_ocaml +open Js_of_ocaml_compiler let split_primitives p = let len = String.length p in @@ -21,24 +21,25 @@ let split_primitives p = let setup = lazy ( Hashtbl.add Toploop.directive_table "enable" - (Toploop.Directive_string Option.Optim.enable); + (Toploop.Directive_string Config.Flag.enable); Hashtbl.add Toploop.directive_table "disable" - (Toploop.Directive_string Option.Optim.disable); + (Toploop.Directive_string Config.Flag.disable); Hashtbl.add Toploop.directive_table "debug_on" - (Toploop.Directive_string Option.Debug.enable); + (Toploop.Directive_string Debug.enable); Hashtbl.add Toploop.directive_table "debug_off" - (Toploop.Directive_string Option.Debug.disable); + (Toploop.Directive_string Debug.disable); Hashtbl.add Toploop.directive_table "tailcall" - (Toploop.Directive_string (Option.Param.set "tc")); + (Toploop.Directive_string (Config.Param.set "tc")); (* Workaround Marshal bug triggered by includemod.ml:607 *) Clflags.error_size := 0 ; (* Disable inlining of JSOO which may blow the JS stack *) - Option.Optim.disable "inline" ; + Config.Flag.disable "inline" ; Topdirs.dir_directory "/cmis"; let initial_primitive_count = Array.length (split_primitives (Symtable.data_primitive_names ())) in let compile s = + let s = String.concat "" (Array.to_list s) in let prims = split_primitives (Symtable.data_primitive_names ()) in let unbound_primitive p = @@ -70,11 +71,18 @@ let setup = lazy ( Format.(pp_print_flush std_formatter ()); Format.(pp_print_flush err_formatter ()); flush stdout; flush stderr; - res))) + res)); + Js.Unsafe.global##.toplevelReloc := Js.Unsafe.callback (fun name -> + let name = Js.to_string name in + Js_of_ocaml_compiler.Ocaml_compiler.Symtable.reloc_ident name); + ()) + +let initialize cmi_dirs = + List.iter Topdirs.dir_directory cmi_dirs; + Lazy.force setup; + Toploop.initialize_toplevel_env (); + Toploop.input_name := "//toplevel//" -let initialize () = - Lazy.force setup ; - Toploop.initialize_toplevel_env () type redirection = { channel : out_channel ; diff --git a/src/toploop/toploop_jsoo.mli b/src/toploop/toploop_jsoo.mli index 88fb2a428..43dd927b6 100644 --- a/src/toploop/toploop_jsoo.mli +++ b/src/toploop/toploop_jsoo.mli @@ -6,8 +6,9 @@ * Learn-OCaml is distributed under the terms of the MIT license. See the * included LICENSE file for details. *) -(** To be called before using any [Toploop] function. *) -val initialize: unit -> unit +(** To be called before using any [Toploop] function. Takes cmi dirs ([-I]) as + argument*) +val initialize: string list -> unit (** Materializes an output channel redirection. *) type redirection diff --git a/src/toploop/toploop_results.ml b/src/toploop/toploop_results.ml index 0fe6b7328..d485453c4 100644 --- a/src/toploop/toploop_results.ml +++ b/src/toploop/toploop_results.ml @@ -6,19 +6,29 @@ * Learn-OCaml is distributed under the terms of the MIT license. See the * included LICENSE file for details. *) +type loc = Location.t + +type msg = Location.t * string + +type warning = msg * msg list +type error = msg * msg list + type 'a toplevel_result = - (* ('a * warning list, error * warning list) result = *) | Ok of 'a * warning list | Error of error * warning list -and error = - { msg: string; - locs: loc list; - if_highlight: string; } +let of_msg msg = + msg.Location.loc, + (msg.Location.txt Format.str_formatter; Format.flush_str_formatter ()) +let to_msg (loc, txt) = { Location.loc; txt = Format.dprintf "%s" txt } -and warning = error +let of_report { Location.kind = _; main; sub } = + of_msg main, List.map of_msg sub +let x_to_report kind (main, sub) = + { Location.kind; main = to_msg main; sub = List.map to_msg sub } +let to_warning = x_to_report (Location.Report_warning "") +let to_error = x_to_report Location.Report_error -and loc = { - loc_start: int * int; - loc_end: int * int; -} +let to_report: 'a toplevel_result -> ('b, 'c) result = function + | Ok (x, warns) -> Stdlib.Ok (x, List.map to_warning warns) + | Error (err, warns) -> Stdlib.Error (to_error err, List.map to_warning warns) diff --git a/src/toploop/toploop_results.mli b/src/toploop/toploop_results.mli index 0fe6b7328..0ed75d63a 100644 --- a/src/toploop/toploop_results.mli +++ b/src/toploop/toploop_results.mli @@ -6,19 +6,22 @@ * Learn-OCaml is distributed under the terms of the MIT license. See the * included LICENSE file for details. *) +type loc = Location.t + +type msg = Location.t * string + +type warning = msg * msg list +type error = msg * msg list + type 'a toplevel_result = - (* ('a * warning list, error * warning list) result = *) | Ok of 'a * warning list | Error of error * warning list -and error = - { msg: string; - locs: loc list; - if_highlight: string; } +val of_report: Location.report -> warning -and warning = error +val to_error: error -> Location.report +val to_warning: warning -> Location.report -and loc = { - loc_start: int * int; - loc_end: int * int; -} +val to_report: + 'a toplevel_result -> + ('a * Location.report list, Location.report * Location.report list) result diff --git a/src/utils/build.ocp b/src/utils/build.ocp deleted file mode 100644 index d70e3d464..000000000 --- a/src/utils/build.ocp +++ /dev/null @@ -1,53 +0,0 @@ -begin library "jsutils" - files = [ - "js_utils.ml" ( comp = ppx_js ) - "lwt_request.ml" ( comp = ppx_js ) - ] - requires = [ - "lwt" - "js_of_ocaml.ppx" - "js_of_ocaml.tyxml" - ] -end - -begin program "ppx_ocplib_i18n" - has_asm = true - has_byte = false - requires = [ - "compiler-libs.common" - ] - files = [ - "ppx_ocplib_i18n.ml" ( more_deps = [ "../../translations/fr.po" ] ) - ] -end - -begin library "ocplib_i18n" - comp_requires = "ppx_ocplib_i18n:asm" - requires = "ppx_ocplib_i18n" - has_asm = true - has_byte = true - files = [ - "ocplib_i18n.ml" ( comp = ppx_ocplib_i18n ) - ] -end - -begin library "lwt_utils" - has_asm = true - has_byte = true - requires = [ - "lwt.unix" - ] - files = [ - "lwt_utils.ml" - ] -end - -begin library "xor" - has_asm = true - files = [ - "xor.ml" - ] - requires = [ - "base64" - ] -end diff --git a/src/utils/dune b/src/utils/dune index 51daffeac..51b8db206 100644 --- a/src/utils/dune +++ b/src/utils/dune @@ -2,9 +2,9 @@ (name jsutils) (wrapped false) (flags :standard -warn-error -4-42-44-45-48-33-27-32-34) - (libraries lwt js_of_ocaml.ppx js_of_ocaml.tyxml) + (libraries lwt js_of_ocaml-ppx js_of_ocaml-tyxml) (modules Js_utils Lwt_request) - (preprocess (pps js_of_ocaml.ppx)) + (preprocess (pps js_of_ocaml-ppx)) ) (library @@ -55,4 +55,4 @@ (flags :standard -warn-error A-4-42-44-45-48) (libraries asak lwt learnocaml_store learnocaml_data) (modules learnocaml_partition_create) -) \ No newline at end of file +) diff --git a/src/utils/js_utils.ml b/src/utils/js_utils.ml index ea6d9be6e..9c3b8e9a1 100644 --- a/src/utils/js_utils.ml +++ b/src/utils/js_utils.ml @@ -17,6 +17,7 @@ * along with this program. If not, see . *) open Js_of_ocaml +open Js_of_ocaml_tyxml let doc = Dom_html.document let window = Dom_html.window @@ -1230,4 +1231,4 @@ let worker_with_code code = let _worker url = let open Lwt.Infix in - Lwt_request.get ?headers:None ~url ~args:[] >|= worker_with_code + Lwt_request.get ?headers:None ~url ~args:[] () >|= worker_with_code diff --git a/src/utils/js_utils.mli b/src/utils/js_utils.mli index f3195027a..f79386d95 100644 --- a/src/utils/js_utils.mli +++ b/src/utils/js_utils.mli @@ -17,6 +17,7 @@ * along with this program. If not, see . *) open Js_of_ocaml +open Js_of_ocaml_tyxml val alert: string -> unit val confirm: string -> bool @@ -104,10 +105,10 @@ module Manip : sig val onload: ('a,Dom_html.event) ev val onerror: ('a,Dom_html.event) ev val onabort: ('a,Dom_html.event) ev - val onfocus: ('a,Dom_html.event) ev - val onblur: ('a,Dom_html.event) ev - val onfocus_textarea: ('a,Dom_html.event) ev - val onblur_textarea: ('a,Dom_html.event) ev + val onfocus: ('a,Dom_html.focusEvent) ev + val onblur: ('a,Dom_html.focusEvent) ev + val onfocus_textarea: ('a,Dom_html.focusEvent) ev + val onblur_textarea: ('a,Dom_html.focusEvent) ev val onscroll: ('a,Dom_html.event) ev val onreturn: ('a,Dom_html.keyboardEvent) ev_unit val onchange: ('a,Dom_html.event) ev diff --git a/src/utils/learnocaml_xor.ml b/src/utils/learnocaml_xor.ml index b76861a57..e34464d52 100644 --- a/src/utils/learnocaml_xor.ml +++ b/src/utils/learnocaml_xor.ml @@ -40,6 +40,6 @@ let xor ?prefix str = done; Bytes.to_string str' -let alphabet = Bytes.to_string alphabet -let decode ?prefix str = xor ?prefix @@ B64.decode ~alphabet str -let encode ?prefix str = B64.encode ~alphabet @@ xor ?prefix str +let alphabet = Base64.make_alphabet (Bytes.to_string alphabet) +let decode ?prefix str = xor ?prefix @@ (Base64.decode ~alphabet str |> Result.get_ok) +let encode ?prefix str = Base64.encode ~alphabet @@ xor ?prefix str |> Result.get_ok diff --git a/src/utils/lwt_request.ml b/src/utils/lwt_request.ml index 1401e5acd..7b8dea9ec 100644 --- a/src/utils/lwt_request.ml +++ b/src/utils/lwt_request.ml @@ -14,7 +14,10 @@ let url_encode_list l = String.concat "&" (List.map (fun (name, arg) -> Printf.sprintf "%s=%s" name (Url.urlencode arg)) l) -let get ?(headers=[]) ~url ~args = +let resp_text req = + Js.to_string @@ Js.Opt.get req##.responseText (fun () -> Js.string "") + +let get ?(headers=[]) ~url ~args () = let (res, w) = Lwt.task () in let req = XmlHttpRequest.create () in let url = match args with @@ -27,11 +30,12 @@ let get ?(headers=[]) ~url ~args = headers; let callback () = match req##.status with - | 200 -> Lwt.wakeup w (Js.to_string req##.responseText) + | 200 -> Lwt.wakeup w (resp_text req) | 204 -> Lwt.wakeup w "" | code (* including 0 *) -> - Lwt.wakeup_exn w - (Request_failed (code, Js.to_string req##.responseText)) in + Lwt.wakeup_exn w @@ + Request_failed (code, Js.Opt.case req##.responseText (fun () -> "") Js.to_string) + in req##.onreadystatechange := Js.wrap_callback (fun _ -> (match req##.readyState with XmlHttpRequest.DONE -> callback () @@ -40,7 +44,7 @@ let get ?(headers=[]) ~url ~args = Lwt.on_cancel res (fun () -> req##abort); res -let post ?(headers=[]) ?(get_args=[]) ~url ~body = +let post ?(headers=[]) ?(get_args=[]) ~url ~body () = let (res, w) = Lwt.task () in let req = XmlHttpRequest.create () in let url = match get_args with @@ -53,10 +57,12 @@ let post ?(headers=[]) ?(get_args=[]) ~url ~body = headers; let callback () = match req##.status with - | 200 -> Lwt.wakeup w (Js.to_string req##.responseText) + | 200 -> Lwt.wakeup w (resp_text req) | 204 -> Lwt.wakeup w "" - | code (* including 0 *) -> Lwt.wakeup_exn w - (Request_failed (code, Js.to_string req##.responseText)) + | code (* including 0 *) -> + Lwt.wakeup_exn w + (Request_failed (code, Js.Opt.case req##.responseText + (fun () -> "") Js.to_string)) in req##.onreadystatechange := Js.wrap_callback (fun _ -> (match req##.readyState with diff --git a/src/utils/lwt_request.mli b/src/utils/lwt_request.mli index 67a7012be..3e5f9a1ac 100644 --- a/src/utils/lwt_request.mli +++ b/src/utils/lwt_request.mli @@ -11,8 +11,8 @@ exception Request_failed of (int * string) val post: ?headers:(string * string) list -> ?get_args:(string * string) list -> - url:string -> body:string option -> string Lwt.t + url:string -> body:string option -> unit -> string Lwt.t val get: ?headers:(string * string) list -> - url:string -> args:(string * string) list -> string Lwt.t + url:string -> args:(string * string) list -> unit -> string Lwt.t diff --git a/src/utils/ppx_ocplib_i18n.ml b/src/utils/ppx_ocplib_i18n.ml index 6a235b7ce..fd5bfab09 100644 --- a/src/utils/ppx_ocplib_i18n.ml +++ b/src/utils/ppx_ocplib_i18n.ml @@ -101,7 +101,7 @@ let dump_pot () = Format.pp_print_string fmt "#:"; List.iter (fun l -> Format.pp_print_char fmt ' '; - Location.print_compact fmt l) + Location.print_loc fmt l) locs; Format.fprintf fmt "\nmsgid %S\n" s; Format.fprintf fmt "msgstr \"\"\n\n"; diff --git a/static/fonts/get_fontin.sh b/static/fonts/get_fontin.sh index cf9ec98bc..92c80af10 100644 --- a/static/fonts/get_fontin.sh +++ b/static/fonts/get_fontin.sh @@ -1,11 +1,11 @@ -#!/bin/sh +#!/bin/sh -e if ! which sfnt2woff ; then echo missing tool sfnt2woff ; exit 1 ; fi rm -rf TMP ; mkdir TMP ; cd TMP home='http://www.exljbris.com/fontin.html' -for url in `wget $home -O - | tr "\"'" "\n\n" | grep .zip` ; do wget $url ; done +for url in `wget --no-check-certificate $home -O - | tr "\"'" "\n\n" | grep .zip` ; do wget --no-check-certificate $url ; done for zip in *.zip ; do unzip $zip ; done for i in Bold Italic Regular SmallCaps ; do diff --git a/translations/fr.po b/translations/fr.po index 9b1fdb7b1..088128dbd 100644 --- a/translations/fr.po +++ b/translations/fr.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: learn-ocaml ~dev\n" -"PO-Revision-Date: 2020-01-01 19:29+0100\n" +"PO-Revision-Date: 2021-07-26 10:51+0200\n" "Last-Translator: Louis Gesbert \n" "Language-Team: OCamlPro\n" "Language: french\n" @@ -13,354 +13,339 @@ msgstr "" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -#: src/grader/learnocaml_report.ml:240,50--66 -#: src/grader/learnocaml_report.ml:595,59--75 +#: File "src/grader/learnocaml_report.ml", line 240, characters 50-66 595, +#: 59-75 msgid "(minimum mark)" msgstr "(note minimale)" -#: src/grader/learnocaml_report.ml:250,55--74 +#: File "src/grader/learnocaml_report.ml", line 250, characters 55-74 msgid "Completed, %d pts" msgstr "Terminé, %d pts" -#: src/grader/learnocaml_report.ml:254,38--46 -#: src/grader/learnocaml_report.ml:258,67--75 +#: File "src/grader/learnocaml_report.ml", line 254, characters 38-46 258, +#: 67-75 msgid "Failed" msgstr "Échoué" -#: src/grader/learnocaml_report.ml:262,55--75 +#: File "src/grader/learnocaml_report.ml", line 262, characters 55-75 msgid "Incomplete, %d pts" msgstr "Incomplet, %d pts" -#: src/grader/learnocaml_report.ml:287,26--43 +#: File "src/grader/learnocaml_report.ml", line 287, characters 26-43 msgid "Exercise failed" msgstr "Exercice échoué" -#: src/grader/learnocaml_report.ml:289,31--37 +#: File "src/grader/learnocaml_report.ml", line 289, characters 31-37 msgid "0 pt" msgstr "0 pt" -#: src/grader/learnocaml_report.ml:291,26--45 +#: File "src/grader/learnocaml_report.ml", line 291, characters 26-45 msgid "Exercise complete" msgstr "Exercice terminé" -#: src/grader/learnocaml_report.ml:293,49--57 -#: src/grader/learnocaml_report.ml:297,49--57 +#: File "src/grader/learnocaml_report.ml", line 293, characters 49-57 297, msgid "%d pts" msgstr "%d pts" -#: src/grader/learnocaml_report.ml:295,26--47 +#: File "src/grader/learnocaml_report.ml", line 295, characters 26-47 msgid "Exercise incomplete" msgstr "Exercice incomplet" -#: src/grader/learnocaml_report.ml:563,56--78 +#: File "src/grader/learnocaml_report.ml", line 563, characters 56-78 msgid "@[Failure: %a@]" msgstr "@[Échec: %a@]" -#: src/grader/learnocaml_report.ml:564,56--78 +#: File "src/grader/learnocaml_report.ml", line 564, characters 56-78 msgid "@[Warning: %a@]" msgstr "@[Avertissement: %a@]" -#: src/grader/learnocaml_report.ml:566,58--82 +#: File "src/grader/learnocaml_report.ml", line 566, characters 58-82 msgid "@[Important: %a@]" msgstr "@[Important: %a@]" -#: src/grader/learnocaml_report.ml:567,58--83 +#: File "src/grader/learnocaml_report.ml", line 567, characters 58-83 msgid "@[Success %d: %a@]" msgstr "@[Réussite %d: %a@]" -#: src/grader/learnocaml_report.ml:568,58--83 +#: File "src/grader/learnocaml_report.ml", line 568, characters 58-83 msgid "@[Penalty %d: %a@]" msgstr "@[Pénalité %d: %a@]" -#: src/app/learnocaml_common.ml:67,21--37 +#: File "src/app/learnocaml_common.ml", line 71, characters 21-37 msgid "INTERNAL ERROR" msgstr "ERREUR INTERNE" -#: src/app/learnocaml_common.ml:102,50--54 -#: src/app/learnocaml_common.ml:136,33--37 -#: src/app/learnocaml_common.ml:142,36--40 +#: File "src/app/learnocaml_common.ml", line 106, characters 50-54 140, 33-37 +#: 146, 36-40 msgid "OK" msgstr "OK" -#: src/app/learnocaml_common.ml:133,21--28 +#: File "src/app/learnocaml_common.ml", line 137, characters 21-28 msgid "ERROR" msgstr "ERREUR" -#: src/app/learnocaml_common.ml:136,58--66 -#: src/app/learnocaml_common.ml:414,12--20 -#: src/app/learnocaml_index_main.ml:574,17--25 +#: File "src/app/learnocaml_common.ml", line 140, characters 58-66 418, 12-20 +#: "src/app/learnocaml_index_main.ml", 583, 17-25 msgid "Cancel" msgstr "Annuler" -#: src/app/learnocaml_common.ml:406,26--41 -#: src/app/learnocaml_index_main.ml:569,32--47 +#: File "src/app/learnocaml_common.ml", line 410, characters 26-41 +#: "src/app/learnocaml_index_main.ml", 578, 32-47 msgid "REQUEST ERROR" msgstr "ERREUR DE REQUÊTE" -#: src/app/learnocaml_common.ml:407,25--62 -#: src/app/learnocaml_index_main.ml:570,31--68 +#: File "src/app/learnocaml_common.ml", line 411, characters 22-59 +#: "src/app/learnocaml_index_main.ml", 579, 28-65 msgid "Could not retrieve data from server" msgstr "Échec lors du téléchargement des données du serveur" -#: src/app/learnocaml_common.ml:410,12--19 -#: src/app/learnocaml_common.ml:450,11--18 -#: src/app/learnocaml_index_main.ml:573,17--24 +#: File "src/app/learnocaml_common.ml", line 414, characters 12-19 454, 11-18 +#: "src/app/learnocaml_index_main.ml", 582, 17-24 msgid "Retry" msgstr "Réessayer" -#: src/app/learnocaml_common.ml:413,25--33 -#: src/app/learnocaml_common.ml:451,11--19 +#: File "src/app/learnocaml_common.ml", line 417, characters 25-33 455, 11-19 msgid "Ignore" msgstr "Ignorer" -#: src/app/learnocaml_common.ml:446,26--39 +#: File "src/app/learnocaml_common.ml", line 450, characters 26-39 msgid "SYNC FAILED" msgstr "ECHEC DE LA SYNCHRONISATION" -#: src/app/learnocaml_common.ml:447,25--69 +#: File "src/app/learnocaml_common.ml", line 451, characters 22-66 msgid "Could not synchronise save with the server" msgstr "Les données n'ont pas pu être synchronisées avec le serveur" -#: src/app/learnocaml_common.ml:499,39--50 +#: File "src/app/learnocaml_common.ml", line 510, characters 39-50 msgid "%dd %02dh" msgstr "%dj %02dh" -#: src/app/learnocaml_common.ml:500,40--51 +#: File "src/app/learnocaml_common.ml", line 511, characters 40-51 msgid "%02d:%02d" msgstr "%02d:%02d" -#: src/app/learnocaml_common.ml:501,23--36 +#: File "src/app/learnocaml_common.ml", line 512, characters 23-36 msgid "0:%02d:%02d" msgstr "0:%02d:%02d" -#: src/app/learnocaml_common.ml:532,34--55 -#: src/app/learnocaml_common.ml:1015,38--59 +#: File "src/app/learnocaml_common.ml", line 543, characters 34-55 1034, 38-59 msgid "difficulty: %d / 40" msgstr "difficulté: %d / 40" -#: src/app/learnocaml_common.ml:567,30--75 +#: File "src/app/learnocaml_common.ml", line 578, characters 30-75 msgid "No description available for this exercise." msgstr "Aucune description pour cet exercice." -#: src/app/learnocaml_common.ml:589,32--41 -#: src/app/learnocaml_index_main.ml:123,57--66 +#: File "src/app/learnocaml_common.ml", line 601, characters 32-41 +#: "src/app/learnocaml_index_main.ml", 132, 54-63 msgid "project" msgstr "projet" -#: src/app/learnocaml_common.ml:590,32--41 -#: src/app/learnocaml_index_main.ml:124,57--66 +#: File "src/app/learnocaml_common.ml", line 602, characters 32-41 +#: "src/app/learnocaml_index_main.ml", 133, 54-63 msgid "problem" msgstr "problème" -#: src/app/learnocaml_common.ml:591,33--43 -#: src/app/learnocaml_index_main.ml:125,58--68 +#: File "src/app/learnocaml_common.ml", line 603, characters 33-43 +#: "src/app/learnocaml_index_main.ml", 134, 55-65 msgid "exercise" msgstr "exercice" -#: src/app/learnocaml_common.ml:743,26--33 +#: File "src/app/learnocaml_common.ml", line 755, characters 26-33 msgid "Clear" msgstr "Effacer" -#: src/app/learnocaml_common.ml:748,25--32 -#: src/app/learnocaml_common.ml:869,24--31 +#: File "src/app/learnocaml_common.ml", line 760, characters 25-32 881, 24-31 msgid "Reset" msgstr "Réinitialiser" -#: src/app/learnocaml_common.ml:753,22--35 +#: File "src/app/learnocaml_common.ml", line 765, characters 22-35 msgid "Eval phrase" msgstr "Évaluer la phrase" -#: src/app/learnocaml_common.ml:768,24--51 +#: File "src/app/learnocaml_common.ml", line 780, characters 24-51 msgid "Preparing the environment" msgstr "Préparation de l'environnement" -#: src/app/learnocaml_common.ml:769,39--47 -#: src/app/learnocaml_common.ml:774,37--45 +#: File "src/app/learnocaml_common.ml", line 781, characters 39-47 786, 37-45 msgid "Editor" msgstr "Éditeur" -#: src/app/learnocaml_common.ml:770,41--51 -#: src/app/learnocaml_index_main.ml:692,30--40 +#: File "src/app/learnocaml_common.ml", line 782, characters 41-51 +#: "src/app/learnocaml_index_main.ml", 689, 30-40 msgid "Toplevel" msgstr "Toplevel" -#: src/app/learnocaml_common.ml:771,39--47 -#: src/app/learnocaml_common.ml:783,39--47 -#: src/app/learnocaml_exercise_main.ml:51,33--41 -#: src/app/learnocaml_exercise_main.ml:55,33--41 -#: src/app/learnocaml_exercise_main.ml:60,33--41 -#: src/app/learnocaml_student_view.ml:381,31--39 -#: src/app/learnocaml_student_view.ml:394,33--41 -#: src/app/learnocaml_student_view.ml:398,33--41 -#: src/app/learnocaml_student_view.ml:403,33--41 +#: File "src/app/learnocaml_common.ml", line 783, characters 39-47 795, +#: "src/app/learnocaml_exercise_main.ml", 58, 30-38 62, 67, +#: "src/app/learnocaml_student_view.ml", 383, 28-36 396, 400, 405, msgid "Report" msgstr "Rapport" -#: src/app/learnocaml_common.ml:772,37--47 +#: File "src/app/learnocaml_common.ml", line 784, characters 37-47 msgid "Exercise" msgstr "Exercice" -#: src/app/learnocaml_common.ml:773,37--46 +#: File "src/app/learnocaml_common.ml", line 785, characters 37-46 msgid "Details" msgstr "Détails" -#: src/app/learnocaml_common.ml:775,27--70 +#: File "src/app/learnocaml_common.ml", line 787, characters 27-70 msgid "Click the Grade button to get your report" msgstr "Cliquez sur le bouton Noter pour obtenir votre rapport" -#: src/app/learnocaml_common.ml:780,22--44 +#: File "src/app/learnocaml_common.ml", line 792, characters 22-44 msgid "Loading student data" msgstr "Chargement des informations sur les étudiants" -#: src/app/learnocaml_common.ml:781,38--45 +#: File "src/app/learnocaml_common.ml", line 793, characters 38-45 msgid "Stats" msgstr "Statistiques" -#: src/app/learnocaml_common.ml:782,37--48 -#: src/app/learnocaml_exercise_main.ml:195,23--34 -#: src/app/learnocaml_index_main.ml:689,48--59 -#: src/app/learnocaml_teacher_tab.ml:327,21--32 +#: File "src/app/learnocaml_common.ml", line 794, characters 37-48 +#: "src/app/learnocaml_index_main.ml", 686, 29-40 +#: "src/app/learnocaml_teacher_tab.ml", 329, 18-29 +#: "src/app/learnocaml_exercise_main.ml", 202, 23-34 msgid "Exercises" msgstr "Exercices" -#: src/app/learnocaml_common.ml:784,37--46 +#: File "src/app/learnocaml_common.ml", line 796, characters 37-46 msgid "Subject" msgstr "Énoncé" -#: src/app/learnocaml_common.ml:785,39--47 +#: File "src/app/learnocaml_common.ml", line 797, characters 39-47 msgid "Answer" msgstr "Réponse" -#: src/app/learnocaml_common.ml:870,22--42 +#: File "src/app/learnocaml_common.ml", line 882, characters 22-42 msgid "START FROM SCRATCH" msgstr "TOUT RECOMMENCER" -#: src/app/learnocaml_common.ml:871,19--68 +#: File "src/app/learnocaml_common.ml", line 883, characters 16-65 msgid "This will discard all your edits. Are you sure?" msgstr "Toutes vos modifications seront perdues. Vous êtes sûr·e ?" -#: src/app/learnocaml_common.ml:878,27--37 +#: File "src/app/learnocaml_common.ml", line 890, characters 27-37 msgid "Download" msgstr "Télécharger" -#: src/app/learnocaml_common.ml:886,22--33 +#: File "src/app/learnocaml_common.ml", line 898, characters 22-33 msgid "Eval code" msgstr "Évaluer le code" -#: src/app/learnocaml_common.ml:893,23--29 +#: File "src/app/learnocaml_common.ml", line 905, characters 23-29 msgid "Sync" msgstr "Sync" -#: src/app/learnocaml_common.ml:946,37--52 +#: File "src/app/learnocaml_common.ml", line 962, characters 34-49 msgid "OCaml prelude" msgstr "Prélude OCaml" -#: src/app/learnocaml_common.ml:953,62--68 +#: File "src/app/learnocaml_common.ml", line 969, characters 59-65 msgid "Hide" msgstr "Cacher" -#: src/app/learnocaml_common.ml:960,62--68 +#: File "src/app/learnocaml_common.ml", line 976, characters 59-65 msgid "Show" msgstr "Montrer" -#: src/app/learnocaml_common.ml:981,19--37 +#: File "src/app/learnocaml_common.ml", line 1000, characters 18-36 msgid "Enter the secret" msgstr "Entrez le secret" -#: src/app/learnocaml_common.ml:1021,25--38 +#: File "src/app/learnocaml_common.ml", line 1040, characters 22-35 msgid "Difficulty:" msgstr "Difficulté :" -#: src/app/learnocaml_common.ml:1035,42--52 +#: File "src/app/learnocaml_common.ml", line 1054, characters 39-49 msgid "Kind: %s" msgstr "Type : %s" -#: src/app/learnocaml_common.ml:1176,46--59 +#: File "src/app/learnocaml_common.ml", line 1195, characters 46-59 msgid "Identifier:" msgstr "Identifiant de l'exercice :" -#: src/app/learnocaml_common.ml:1180,48--57 +#: File "src/app/learnocaml_common.ml", line 1199, characters 48-57 msgid "Author:" msgstr "Auteur :" -#: src/app/learnocaml_common.ml:1181,47--57 +#: File "src/app/learnocaml_common.ml", line 1200, characters 47-57 msgid "Authors:" msgstr "Auteurs :" -#: src/app/learnocaml_common.ml:1186,31--48 +#: File "src/app/learnocaml_common.ml", line 1205, characters 31-48 msgid "Skills trained:" msgstr "Compétences pratiquées :" -#: src/app/learnocaml_common.ml:1190,31--49 +#: File "src/app/learnocaml_common.ml", line 1209, characters 31-49 msgid "Skills required:" msgstr "Compétences requises :" -#: src/app/learnocaml_common.ml:1195,36--57 +#: File "src/app/learnocaml_common.ml", line 1214, characters 36-57 msgid "Previous exercises:" msgstr "Exercices précédents :" -#: src/app/learnocaml_common.ml:1198,35--52 +#: File "src/app/learnocaml_common.ml", line 1217, characters 35-52 msgid "Next exercises:" msgstr "Exercices suivants :" -#: src/app/learnocaml_common.ml:1203,29--39 +#: File "src/app/learnocaml_common.ml", line 1222, characters 26-36 msgid "Metadata" msgstr "Métadonnées" -#: src/toplevel/learnocaml_toplevel.ml:77,7--41 +#: File "src/toplevel/learnocaml_toplevel.ml", line 79, characters 7-41 msgid "The toplevel has been cleared.\n" msgstr "Le toplevel a été nettoyé.\n" -#: src/toplevel/learnocaml_toplevel.ml:264,36--49 +#: File "src/toplevel/learnocaml_toplevel.ml", line 271, characters 36-49 msgid "%d seconds!" msgstr "%d secondes !" -#: src/toplevel/learnocaml_toplevel.ml:267,23--33 +#: File "src/toplevel/learnocaml_toplevel.ml", line 274, characters 20-30 msgid "Kill it!" msgstr "Le terminer !" -#: src/toplevel/learnocaml_toplevel.ml:277,27--43 +#: File "src/toplevel/learnocaml_toplevel.ml", line 284, characters 24-40 msgid "Infinite loop?" msgstr "Boucle infinie ?" -#: src/toplevel/learnocaml_toplevel.ml:279,26--69 +#: File "src/toplevel/learnocaml_toplevel.ml", line 286, characters 23-66 msgid "The toplevel has not been responding for " msgstr "Le toplevel ne répond plus depuis " -#: src/toplevel/learnocaml_toplevel.ml:281,26--37 -#: src/toplevel/learnocaml_toplevel.ml:285,26--37 +#: File "src/toplevel/learnocaml_toplevel.ml", line 288, characters 23-34 292, msgid " seconds." msgstr " secondes." -#: src/toplevel/learnocaml_toplevel.ml:283,26--49 +#: File "src/toplevel/learnocaml_toplevel.ml", line 290, characters 23-46 msgid "It will be killed in " msgstr "Il sera terminé dans " -#: src/toplevel/learnocaml_toplevel.ml:314,23--37 +#: File "src/toplevel/learnocaml_toplevel.ml", line 321, characters 20-34 msgid "Show anyway!" msgstr "Afficher quand même !" -#: src/toplevel/learnocaml_toplevel.ml:316,23--37 +#: File "src/toplevel/learnocaml_toplevel.ml", line 323, characters 20-34 msgid "Hide output!" msgstr "Masquer la sortie !" -#: src/toplevel/learnocaml_toplevel.ml:325,27--44 +#: File "src/toplevel/learnocaml_toplevel.ml", line 332, characters 24-41 msgid "Flooded output!" msgstr "La sortie déborde !" -#: src/toplevel/learnocaml_toplevel.ml:328,30--69 +#: File "src/toplevel/learnocaml_toplevel.ml", line 335, characters 30-69 msgid "Your code is flooding the %s channel." msgstr "Votre code submerge le canal %s." -#: src/toplevel/learnocaml_toplevel.ml:330,26--51 +#: File "src/toplevel/learnocaml_toplevel.ml", line 337, characters 23-48 msgid "It has already printed " msgstr "Il a déjà affiché " -#: src/toplevel/learnocaml_toplevel.ml:332,26--35 +#: File "src/toplevel/learnocaml_toplevel.ml", line 339, characters 23-32 msgid " bytes." msgstr " octets." -#: src/toplevel/learnocaml_toplevel.ml:368,44--80 +#: File "src/toplevel/learnocaml_toplevel.ml", line 375, characters 44-80 msgid "" "\n" "Interrupted output channel %s.\n" @@ -368,7 +353,7 @@ msgstr "" "\n" "Canal de sortie %s interrompu.\n" -#: src/toplevel/learnocaml_toplevel.ml:384,5--464 +#: File "src/toplevel/learnocaml_toplevel.ml", lines 407-412, characters 5-39 msgid "" "Printf.printf \"Welcome to OCaml %s\\n%!\" (Sys.ocaml_version);\n" "print_endline \" - type your OCaml phrase in the box below and press " @@ -390,163 +375,63 @@ msgstr "" "print_endline \" - utilisez [Ctrl-\\xe2\\x86\\x91] / [Ctrl-\\xe2\\x86\\x93] " "pour naviguer dans l'historique\";;" -#: src/toplevel/learnocaml_toplevel.ml:494,11--43 +#: File "src/toplevel/learnocaml_toplevel.ml", line 518, characters 11-43 msgid "The toplevel has been reset.\n" msgstr "Le toplevel a été redémarré.\n" -#: src/app/learnocaml_exercise_main.ml:24,20--79 -msgid "WARNING: You have an older grader version than the server" -msgstr "" -"ATTENTION: La version locale du grader est plus ancienne que celle du serveur" - -#: src/app/learnocaml_exercise_main.ml:25,23--41 -msgid "Refresh the page" -msgstr "Actualiser la page" - -#: src/app/learnocaml_exercise_main.ml:27,27--49 -msgid "I will do it myself!" -msgstr "Je sais le faire moi-même!" - -#: src/app/learnocaml_exercise_main.ml:28,22--178 -msgid "" -"The server has been updated, please refresh the page to make sure you are " -"using the latest version of Learn-OCaml server (none of your work will be " -"lost)." -msgstr "" -"Le serveur a été mis à jour, veuillez actualiser la page pour être sûr " -"d'utiliser la dernière version du serveur Learn-OCaml (votre travail ne sera " -"pas perdu)." - -#: src/app/learnocaml_exercise_main.ml:85,18--29 -msgid "TIME'S UP" -msgstr "TEMPS ÉCOULÉ" - -#: src/app/learnocaml_exercise_main.ml:86,7--119 -msgid "" -"The deadline for this exercise has expired. Any changes you make from now on " -"will remain local only." -msgstr "" -"La date limite de rendu de cet exercice est passée. Vos changements ne " -"seront plus sauvegardés sur le serveur." - -#: src/app/learnocaml_exercise_main.ml:123,25--49 -#: src/app/learnocaml_playground_main.ml:40,19--43 -msgid "loading the prelude..." -msgstr "Chargement du prélude..." - -#: src/app/learnocaml_exercise_main.ml:128,41--59 -#: src/app/learnocaml_playground_main.ml:43,31--49 -msgid "error in prelude" -msgstr "erreur dans le prélude" - -#: src/app/learnocaml_exercise_main.ml:207,28--37 -#: src/app/learnocaml_playground_main.ml:77,28--37 -msgid "Compile" -msgstr "Compiler" - -#: src/app/learnocaml_exercise_main.ml:211,25--33 -msgid "Grade!" -msgstr "Noter!" - -#: src/app/learnocaml_exercise_main.ml:216,51--58 -msgid "abort" -msgstr "abandonner" - -#: src/app/learnocaml_exercise_main.ml:220,38--73 -msgid "Grading is taking a lot of time, " -msgstr "La notation prend longtemps, " - -#: src/app/learnocaml_exercise_main.ml:226,38--60 -msgid "Launching the grader" -msgstr "Lancement de la notation" - -#: src/app/learnocaml_exercise_main.ml:249,60--86 -msgid "Grading aborted by user." -msgstr "Notation annulée par l'utilisateur." - -#: src/app/learnocaml_exercise_main.ml:270,38--59 -msgid "Error in your code." -msgstr "Erreur dans le code." - -#: src/app/learnocaml_exercise_main.ml:271,27--85 -msgid "Cannot start the grader if your code does not typecheck." -msgstr "La notation ne peut être lancée si le code ne type pas." - -#: src/grader/grader_jsoo_worker.ml:49,17--44 -msgid "Error in your solution:\n" -msgstr "Erreur dans votre solution:\n" - -#: src/grader/grader_jsoo_worker.ml:51,17--41 -msgid "Error in the exercise " -msgstr "Erreur dans l'exercice " - -#: src/grader/grader_jsoo_worker.ml:53,17--71 -msgid "" -"Internal error:\n" -"The grader did not return a report." -msgstr "" -"Erreur interne:\n" -"Le moteur de notation n'a pas retourné de rapport." - -#: src/grader/grader_jsoo_worker.ml:55,17--38 -msgid "Unexpected error:\n" -msgstr "Erreur inattendue:\n" - -#: src/app/learnocaml_index_main.ml:64,18--37 +#: File "src/app/learnocaml_index_main.ml", line 73, characters 18-37 msgid "Loading exercises" msgstr "Chargement des exercices" -#: src/app/learnocaml_index_main.ml:97,32--49 +#: File "src/app/learnocaml_index_main.ml", line 106, characters 32-49 msgid "Exercise closed" msgstr "Exercice fermé" -#: src/app/learnocaml_index_main.ml:98,47--62 +#: File "src/app/learnocaml_index_main.ml", line 107, characters 47-62 msgid "Time left: %s" msgstr "Temps restant: %s" -#: src/app/learnocaml_index_main.ml:145,31--64 +#: File "src/app/learnocaml_index_main.ml", line 154, characters 28-61 msgid "No open exercises at the moment" msgstr "Aucun exercice n'est encore ouvert" -#: src/app/learnocaml_index_main.ml:152,18--38 +#: File "src/app/learnocaml_index_main.ml", line 161, characters 18-38 msgid "Loading playground" msgstr "Chargement du bac-à-sable" -#: src/app/learnocaml_index_main.ml:178,18--35 +#: File "src/app/learnocaml_index_main.ml", line 187, characters 18-35 msgid "Loading lessons" msgstr "Chargement des cours" -#: src/app/learnocaml_index_main.ml:211,37--61 +#: File "src/app/learnocaml_index_main.ml", line 220, characters 37-61 msgid "Running OCaml examples" msgstr "Lancement des exemples d'OCaml" -#: src/app/learnocaml_index_main.ml:252,39--45 -#: src/app/learnocaml_index_main.ml:441,39--45 +#: File "src/app/learnocaml_index_main.ml", line 261, characters 39-45 450, msgid "Prev" msgstr "Prec." -#: src/app/learnocaml_index_main.ml:268,40--46 -#: src/app/learnocaml_index_main.ml:458,40--46 +#: File "src/app/learnocaml_index_main.ml", line 277, characters 40-46 467, msgid "Next" msgstr "Suiv." -#: src/app/learnocaml_index_main.ml:325,18--37 +#: File "src/app/learnocaml_index_main.ml", line 334, characters 18-37 msgid "Loading tutorials" msgstr "Chargement des tutoriels" -#: src/app/learnocaml_index_main.ml:491,18--35 +#: File "src/app/learnocaml_index_main.ml", line 500, characters 18-35 msgid "Launching OCaml" msgstr "Démarrage d'OCaml" -#: src/app/learnocaml_index_main.ml:504,18--40 +#: File "src/app/learnocaml_index_main.ml", line 513, characters 18-40 msgid "Loading student info" msgstr "Chargement des informations sur les étudiants" -#: src/app/learnocaml_index_main.ml:524,22--46 +#: File "src/app/learnocaml_index_main.ml", line 533, characters 22-46 msgid "Your Learn-OCaml token" msgstr "Votre token Learn-OCaml" -#: src/app/learnocaml_index_main.ml:525,21--147 +#: File "src/app/learnocaml_index_main.ml", lines 534-535, characters 18-70 msgid "" "Your token is displayed below. It identifies you and allows to share your " "workspace between devices." @@ -554,90 +439,89 @@ msgstr "" "Votre token est affiché ci-dessous. Il vous identifie et permet de partager " "un même espace de travail entre plusieurs machines." -#: src/app/learnocaml_index_main.ml:527,21--44 +#: File "src/app/learnocaml_index_main.ml", line 536, characters 18-41 msgid "Please write it down." msgstr "Notez-le !" -#: src/app/learnocaml_index_main.ml:565,28--45 +#: File "src/app/learnocaml_index_main.ml", line 574, characters 28-45 msgid "TOKEN NOT FOUND" msgstr "TOKEN NON TROUVÉ" -#: src/app/learnocaml_index_main.ml:566,17--60 +#: File "src/app/learnocaml_index_main.ml", line 575, characters 17-60 msgid "The entered token couldn't be recognised." msgstr "Le token entré n'a pas été reconnu." -#: src/app/learnocaml_index_main.ml:620,7--21 +#: File "src/app/learnocaml_index_main.ml", line 617, characters 7-21 msgid "Connected as" msgstr "Connecté en tant que" -#: src/app/learnocaml_index_main.ml:622,7--19 +#: File "src/app/learnocaml_index_main.ml", line 619, characters 7-19 msgid "Activities" msgstr "Activités" -#: src/app/learnocaml_index_main.ml:624,9--33 +#: File "src/app/learnocaml_index_main.ml", line 621, characters 9-33 msgid "Welcome to Learn OCaml" msgstr "Bienvenue sur Learn OCaml" -#: src/app/learnocaml_index_main.ml:625,31--49 +#: File "src/app/learnocaml_index_main.ml", line 622, characters 31-49 msgid "First connection" msgstr "Première connexion" -#: src/app/learnocaml_index_main.ml:626,38--57 +#: File "src/app/learnocaml_index_main.ml", line 623, characters 38-57 msgid "Choose a nickname" msgstr "Choisissez un identifiant" -#: src/app/learnocaml_index_main.ml:627,38--46 +#: File "src/app/learnocaml_index_main.ml", line 624, characters 38-46 msgid "Secret" msgstr "Secret" -#: src/app/learnocaml_index_main.ml:628,24--42 +#: File "src/app/learnocaml_index_main.ml", line 625, characters 24-42 msgid "Create new token" msgstr "Nouveau token" -#: src/app/learnocaml_index_main.ml:629,24--40 +#: File "src/app/learnocaml_index_main.ml", line 626, characters 24-40 msgid "Returning user" msgstr "Utilisateur existant" -#: src/app/learnocaml_index_main.ml:630,31--49 +#: File "src/app/learnocaml_index_main.ml", line 627, characters 31-49 msgid "Enter your token" msgstr "Entrez votre token" -#: src/app/learnocaml_index_main.ml:631,31--40 +#: File "src/app/learnocaml_index_main.ml", line 628, characters 31-40 msgid "Connect" msgstr "Se connecter" -#: src/app/learnocaml_index_main.ml:639,9--19 -#: src/app/learnocaml_index_main.ml:641,9--19 -#: src/app/learnocaml_teacher_tab.ml:556,25--35 +#: File "src/app/learnocaml_index_main.ml", line 636, characters 9-19 638, +#: "src/app/learnocaml_teacher_tab.ml", 558, 22-32 msgid "Nickname" msgstr "Pseudonyme" -#: src/app/learnocaml_index_main.ml:676,41--62 +#: File "src/app/learnocaml_index_main.ml", line 673, characters 38-59 msgid "Choose an activity." msgstr "Sélectionnez une activité." -#: src/app/learnocaml_index_main.ml:685,30--41 +#: File "src/app/learnocaml_index_main.ml", line 682, characters 30-41 msgid "Try OCaml" msgstr "Try OCaml" -#: src/app/learnocaml_index_main.ml:687,29--38 +#: File "src/app/learnocaml_index_main.ml", line 684, characters 29-38 msgid "Lessons" msgstr "Cours" -#: src/app/learnocaml_index_main.ml:694,32--44 -#: src/app/learnocaml_playground_main.ml:70,23--35 +#: File "src/app/learnocaml_index_main.ml", line 691, characters 32-44 +#: "src/app/learnocaml_playground_main.ml", 73, 23-35 msgid "Playground" msgstr "Bac-à-sable" -#: src/app/learnocaml_index_main.ml:697,28--35 +#: File "src/app/learnocaml_index_main.ml", line 694, characters 28-35 msgid "Teach" msgstr "Enseignement" -#: src/app/learnocaml_index_main.ml:795,15--69 +#: File "src/app/learnocaml_index_main.ml", line 792, characters 15-69 msgid "Be sure to write down your token before logging out:" msgstr "Assurez-vous d'avoir noté votre token :" -#: src/app/learnocaml_index_main.ml:797,15--186 +#: File "src/app/learnocaml_index_main.ml", lines 794-796, characters 15-26 msgid "" "WARNING: the data could not be synchronised with the server. Logging out " "will lose your local changes, be sure you exported a backup." @@ -646,41 +530,40 @@ msgstr "" "En vous déconnectant, vous perdrez tous les changements locaux, à moins " "d'avoir exporté votre espace de travail au préalable." -#: src/app/learnocaml_index_main.ml:801,22--30 -#: src/app/learnocaml_index_main.ml:801,45--53 -#: src/app/learnocaml_index_main.ml:823,9--17 +#: File "src/app/learnocaml_index_main.ml", line 798, characters 22-30 45-53 +#: 820, 9-17 msgid "Logout" msgstr "Déconnexion" -#: src/app/learnocaml_index_main.ml:814,9--21 +#: File "src/app/learnocaml_index_main.ml", line 811, characters 9-21 msgid "Show token" msgstr "Afficher le token" -#: src/app/learnocaml_index_main.ml:817,9--25 +#: File "src/app/learnocaml_index_main.ml", line 814, characters 9-25 msgid "Sync workspace" msgstr "Synchroniser" -#: src/app/learnocaml_index_main.ml:820,9--25 +#: File "src/app/learnocaml_index_main.ml", line 817, characters 9-25 msgid "Export to file" msgstr "Exporter vers un fichier" -#: src/app/learnocaml_index_main.ml:821,9--17 +#: File "src/app/learnocaml_index_main.ml", line 818, characters 9-17 msgid "Import" msgstr "Importer" -#: src/app/learnocaml_index_main.ml:822,9--36 +#: File "src/app/learnocaml_index_main.ml", line 819, characters 9-36 msgid "Download all source files" msgstr "Télécharger tous les fichiers sources" -#: src/app/learnocaml_index_main.ml:828,38--44 +#: File "src/app/learnocaml_index_main.ml", line 825, characters 38-44 msgid "Menu" msgstr "Menu" -#: src/app/learnocaml_teacher_tab.ml:73,20--35 +#: File "src/app/learnocaml_teacher_tab.ml", line 75, characters 20-35 msgid "TEACHER TOKEN" msgstr "TOKEN PROF." -#: src/app/learnocaml_teacher_tab.ml:74,26--105 +#: File "src/app/learnocaml_teacher_tab.ml", lines 76-77, characters 26-42 msgid "" "New teacher token created:\n" "%s\n" @@ -692,255 +575,364 @@ msgstr "" "\n" "Notez-le !" -#: src/app/learnocaml_teacher_tab.ml:255,48--54 +#: File "src/app/learnocaml_teacher_tab.ml", line 257, characters 48-54 msgid "Open" msgstr "Ouvert" -#: src/app/learnocaml_teacher_tab.ml:256,52--60 +#: File "src/app/learnocaml_teacher_tab.ml", line 258, characters 52-60 msgid "Closed" msgstr "Fermé" -#: src/app/learnocaml_teacher_tab.ml:257,58--68 -#: src/app/learnocaml_teacher_tab.ml:258,42--52 +#: File "src/app/learnocaml_teacher_tab.ml", line 259, characters 58-68 260, +#: 42-52 msgid "Assigned" msgstr "Devoir" -#: src/app/learnocaml_teacher_tab.ml:318,52--64 -#: src/app/learnocaml_teacher_tab.ml:338,51--63 +#: File "src/app/learnocaml_teacher_tab.ml", line 320, characters 49-61 340, +#: 48-60 msgid "Loading..." msgstr "Chargement..." -#: src/app/learnocaml_teacher_tab.ml:392,20--41 +#: File "src/app/learnocaml_teacher_tab.ml", line 394, characters 17-38 msgid "any future students" msgstr "tout nouvel étudiant" -#: src/app/learnocaml_teacher_tab.ml:540,21--31 +#: File "src/app/learnocaml_teacher_tab.ml", line 542, characters 18-28 msgid "Students" msgstr "Étudiants" -#: src/app/learnocaml_teacher_tab.ml:550,23--32 +#: File "src/app/learnocaml_teacher_tab.ml", line 552, characters 20-29 msgid "Sort by" msgstr "Tri par" -#: src/app/learnocaml_teacher_tab.ml:558,25--32 +#: File "src/app/learnocaml_teacher_tab.ml", line 560, characters 22-29 msgid "Token" msgstr "Token" -#: src/app/learnocaml_teacher_tab.ml:560,25--40 +#: File "src/app/learnocaml_teacher_tab.ml", line 562, characters 22-37 msgid "Creation date" msgstr "Date d'entrée" -#: src/app/learnocaml_teacher_tab.ml:562,25--31 +#: File "src/app/learnocaml_teacher_tab.ml", line 564, characters 22-28 msgid "Tags" msgstr "Tags" -#: src/app/learnocaml_teacher_tab.ml:567,46--52 +#: File "src/app/learnocaml_teacher_tab.ml", line 569, characters 46-52 msgid "tags" msgstr "tags" -#: src/app/learnocaml_teacher_tab.ml:643,16--28 +#: File "src/app/learnocaml_teacher_tab.ml", line 645, characters 16-28 msgid "1 exercise" msgstr "1 exercice" -#: src/app/learnocaml_teacher_tab.ml:644,32--46 +#: File "src/app/learnocaml_teacher_tab.ml", line 646, characters 32-46 msgid "%d exercises" msgstr "%d exercices" -#: src/app/learnocaml_teacher_tab.ml:647,23--34 +#: File "src/app/learnocaml_teacher_tab.ml", line 649, characters 23-34 msgid "1 student" msgstr "1 étudiant" -#: src/app/learnocaml_teacher_tab.ml:648,39--52 +#: File "src/app/learnocaml_teacher_tab.ml", line 650, characters 39-52 msgid "%d students" msgstr "%d étudiants" -#: src/app/learnocaml_teacher_tab.ml:649,38--52 +#: File "src/app/learnocaml_teacher_tab.ml", line 651, characters 38-52 msgid "%d+ students" msgstr "%d+ étudiants" -#: src/app/learnocaml_teacher_tab.ml:716,48--64 +#: File "src/app/learnocaml_teacher_tab.ml", line 718, characters 45-61 msgid "New assignment" msgstr "Nouveau devoir" -#: src/app/learnocaml_teacher_tab.ml:819,19--31 +#: File "src/app/learnocaml_teacher_tab.ml", line 821, characters 16-28 msgid "Open/Close" msgstr "Ouvrir/Fermer" -#: src/app/learnocaml_teacher_tab.ml:825,47--64 +#: File "src/app/learnocaml_teacher_tab.ml", line 827, characters 47-64 msgid "required skills" msgstr "comp. requises" -#: src/app/learnocaml_teacher_tab.ml:829,47--63 +#: File "src/app/learnocaml_teacher_tab.ml", line 831, characters 47-63 msgid "trained skills" msgstr "comp. travaillées" -#: src/app/learnocaml_teacher_tab.ml:838,39--52 +#: File "src/app/learnocaml_teacher_tab.ml", line 840, characters 36-49 msgid "Assignments" msgstr "Devoirs" -#: src/app/learnocaml_teacher_tab.ml:921,21--28 +#: File "src/app/learnocaml_teacher_tab.ml", line 923, characters 18-25 msgid "Apply" msgstr "Appliquer" -#: src/app/learnocaml_teacher_tab.ml:922,57--66 +#: File "src/app/learnocaml_teacher_tab.ml", line 924, characters 54-63 msgid "Actions" msgstr "Actions" -#: src/app/learnocaml_teacher_tab.ml:925,26--52 +#: File "src/app/learnocaml_teacher_tab.ml", line 927, characters 23-49 msgid "Create new teacher token" msgstr "Créer un nouveau token enseignant" -#: src/app/learnocaml_teacher_tab.ml:927,26--56 +#: File "src/app/learnocaml_teacher_tab.ml", line 929, characters 23-53 msgid "Download student data as CSV" msgstr "Exporter les données étudiants en CSV" -#: src/app/learnocaml_teacher_tab.ml:1099,58--75 +#: File "src/app/learnocaml_teacher_tab.ml", line 1101, characters 55-72 msgid "Unsaved changes" msgstr "Modifications non sauvegardées" -#: src/app/learnocaml_student_view.ml:211,27--57 +#: File "src/app/learnocaml_exercise_main.ml", line 29, characters 22-81 +msgid "WARNING: You have an older grader version than the server" +msgstr "" +"ATTENTION: La version locale du grader est plus ancienne que celle du serveur" + +#: File "src/app/learnocaml_exercise_main.ml", line 30, characters 25-43 +msgid "Refresh the page" +msgstr "Actualiser la page" + +#: File "src/app/learnocaml_exercise_main.ml", line 32, characters 29-51 +msgid "I will do it myself!" +msgstr "Je sais le faire moi-même!" + +#: File "src/app/learnocaml_exercise_main.ml", line 33, characters 24-180 +msgid "" +"The server has been updated, please refresh the page to make sure you are " +"using the latest version of Learn-OCaml server (none of your work will be " +"lost)." +msgstr "" +"Le serveur a été mis à jour, veuillez actualiser la page pour être sûr " +"d'utiliser la dernière version du serveur Learn-OCaml (votre travail ne sera " +"pas perdu)." + +#: File "src/app/learnocaml_exercise_main.ml", line 92, characters 18-29 +msgid "TIME'S UP" +msgstr "TEMPS ÉCOULÉ" + +#: File "src/app/learnocaml_exercise_main.ml", lines 93-94, characters 7-44 +msgid "" +"The deadline for this exercise has expired. Any changes you make from now on " +"will remain local only." +msgstr "" +"La date limite de rendu de cet exercice est passée. Vos changements ne " +"seront plus sauvegardés sur le serveur." + +#: File "src/app/learnocaml_exercise_main.ml", line 130, characters 25-49 +#: "src/app/learnocaml_playground_main.ml", 43, 19-43 +msgid "loading the prelude..." +msgstr "Chargement du prélude..." + +#: File "src/app/learnocaml_exercise_main.ml", line 135, characters 41-59 +#: "src/app/learnocaml_playground_main.ml", 46, 31-49 +msgid "error in prelude" +msgstr "erreur dans le prélude" + +#: File "src/app/learnocaml_exercise_main.ml", line 214, characters 28-37 +#: "src/app/learnocaml_playground_main.ml", 80, +msgid "Compile" +msgstr "Compiler" + +#: File "src/app/learnocaml_exercise_main.ml", line 218, characters 29-37 +msgid "Grade!" +msgstr "Noter!" + +#: File "src/app/learnocaml_exercise_main.ml", line 222, characters 48-55 +msgid "abort" +msgstr "abandonner" + +#: File "src/app/learnocaml_exercise_main.ml", line 226, characters 35-70 +msgid "Grading is taking a lot of time, " +msgstr "La notation prend longtemps, " + +#: File "src/app/learnocaml_exercise_main.ml", line 232, characters 35-57 +msgid "Launching the grader" +msgstr "Lancement de la notation" + +#: File "src/app/learnocaml_exercise_main.ml", line 255, characters 60-86 +msgid "Grading aborted by user." +msgstr "Notation annulée par l'utilisateur." + +#: File "src/app/learnocaml_exercise_main.ml", line 276, characters 38-59 +msgid "Error in your code." +msgstr "Erreur dans le code." + +#: File "src/app/learnocaml_exercise_main.ml", line 277, characters 27-85 +msgid "Cannot start the grader if your code does not typecheck." +msgstr "La notation ne peut être lancée si le code ne type pas." + +#: File "src/app/learnocaml_student_view.ml", line 213, characters 24-54 msgid "Future assignment (starting " msgstr "Devoir à venir (à partir du " -#: src/app/learnocaml_student_view.ml:215,27--52 +#: File "src/app/learnocaml_student_view.ml", line 217, characters 24-49 msgid "Terminated assignment (" msgstr "Devoir terminé (" -#: src/app/learnocaml_student_view.ml:219,27--53 +#: File "src/app/learnocaml_student_view.ml", line 221, characters 24-50 msgid "Ongoing assignment (due " msgstr "Devoir en cours (à rendre le " -#: src/app/learnocaml_student_view.ml:223,27--43 +#: File "src/app/learnocaml_student_view.ml", line 225, characters 24-40 msgid "Open exercises" msgstr "Exercices ouverts" -#: src/app/learnocaml_student_view.ml:304,22--37 +#: File "src/app/learnocaml_student_view.ml", line 306, characters 19-34 msgid "Student stats" msgstr "Statistiques de l'étudiant" -#: src/app/learnocaml_student_view.ml:307,16--28 +#: File "src/app/learnocaml_student_view.ml", line 309, characters 16-28 msgid "completion" msgstr "complétion" -#: src/app/learnocaml_student_view.ml:308,13--62 +#: File "src/app/learnocaml_student_view.ml", line 310, characters 13-62 msgid "The average grade over all accessible exercises" msgstr "Note moyenne sur tous les exercices accessibles" -#: src/app/learnocaml_student_view.ml:310,16--27 +#: File "src/app/learnocaml_student_view.ml", line 312, characters 16-27 msgid "attempted" msgstr "commencés" -#: src/app/learnocaml_student_view.ml:311,13--74 +#: File "src/app/learnocaml_student_view.ml", line 313, characters 13-74 msgid "The amount of accessible exercises that have been attempted" msgstr "La proportion d'exercices accessibles qui ont été commencés" -#: src/app/learnocaml_student_view.ml:313,16--25 +#: File "src/app/learnocaml_student_view.ml", line 315, characters 16-25 msgid "success" msgstr "réussite" -#: src/app/learnocaml_student_view.ml:314,13--57 +#: File "src/app/learnocaml_student_view.ml", line 316, characters 13-57 msgid "The average grade over attempted exercises" msgstr "La note moyenne sur les exercices commencés" -#: src/app/learnocaml_student_view.ml:320,28--68 +#: File "src/app/learnocaml_student_view.ml", line 322, characters 25-65 msgid "success over exercises training skills" msgstr "moyenne sur les exercices entraînant les compétences" -#: src/app/learnocaml_student_view.ml:324,19--59 +#: File "src/app/learnocaml_student_view.ml", line 326, characters 19-59 msgid "Success over exercises training skill " msgstr "Moyenne sur les exercices entraînant la compétence " -#: src/app/learnocaml_student_view.ml:334,28--69 +#: File "src/app/learnocaml_student_view.ml", line 336, characters 25-66 msgid "success over exercises requiring skills" msgstr "moyenne sur les exercices requérant les compétences" -#: src/app/learnocaml_student_view.ml:338,19--60 +#: File "src/app/learnocaml_student_view.ml", line 340, characters 19-60 msgid "Success over exercises requiring skill " msgstr "Moyenne sur les exercices requérant la compétence " -#: src/app/learnocaml_student_view.ml:441,29--70 +#: File "src/app/learnocaml_student_view.ml", line 443, characters 26-67 msgid "GRADE DOESN'T MATCH: cheating suspected" msgstr "NOTE INCOHÉRENTE: suspicion de triche" -#: src/app/learnocaml_student_view.ml:445,28--49 +#: File "src/app/learnocaml_student_view.ml", line 447, characters 25-46 msgid "No report available" msgstr "Aucun rapport" -#: src/app/learnocaml_student_view.ml:472,8--29 +#: File "src/app/learnocaml_student_view.ml", line 474, characters 8-29 msgid "Status of student: " msgstr "Suivi étudiant: " -#: src/grader/grading.ml:16,27--66 +#: File "src/grader/grader_jsoo_worker.ml", line 57, characters 34-67 +msgid "" +"Error in your solution:\n" +"%a\n" +"%!" +msgstr "" +"Erreur dans votre solution:\n" +"%a\n" +"%!" + +#: File "src/grader/grader_jsoo_worker.ml", line 60, characters 34-68 +msgid "" +"Error in the exercise %s\n" +"%a\n" +"%!" +msgstr "" +"Erreur dans l'exercice %s\n" +"%a\n" +"%!" + +#: File "src/grader/grader_jsoo_worker.ml", line 64, characters 17-71 +msgid "" +"Internal error:\n" +"The grader did not return a report." +msgstr "" +"Erreur interne:\n" +"Le moteur de notation n'a pas retourné de rapport." + +#: File "src/grader/grader_jsoo_worker.ml", line 66, characters 17-38 +msgid "Unexpected error:\n" +msgstr "Erreur inattendue:\n" + +#: File "src/grader/grading.ml", line 16, characters 28-67 msgid "" "Exercise definition error %s:\n" -"%s\n" +"%a\n" "%!" msgstr "" "Erreur dans la définition de l'exercice %s:\n" -"%s\n" +"%a\n" "%!" -#: src/grader/grading.ml:22,27--58 +#: File "src/grader/grading.ml", line 22, characters 28-59 msgid "" "Error in user code:\n" "\n" -"%s\n" +"%a\n" "%!" msgstr "" -"Erreur dans le code\n" +"Erreur dans le code:\n" "\n" -"%s\n" +"%a\n" "%!" -#: src/grader/grading.ml:98,38--65 src/grader/grading.ml:108,38--65 -#: src/grader/grading.ml:133,38--65 src/grader/grading.ml:141,38--65 +#: File "src/grader/grading.ml", line 96, characters 38-65 106, 131, 139, msgid "while preparing the tests" msgstr "lors de la préparation des tests" -#: src/grader/grading.ml:102,22--44 +#: File "src/grader/grading.ml", line 100, characters 22-44 msgid "Loading the prelude." msgstr "Chargement du prélude." -#: src/grader/grading.ml:103,38--65 +#: File "src/grader/grading.ml", line 101, characters 38-65 msgid "while loading the prelude" msgstr "lors du chargement du prélude" -#: src/grader/grading.ml:107,22--55 +#: File "src/grader/grading.ml", line 105, characters 22-55 msgid "Preparing the test environment." msgstr "Préparation de l'environnement de test." -#: src/grader/grading.ml:112,22--42 +#: File "src/grader/grading.ml", line 110, characters 22-42 msgid "Loading your code." msgstr "Chargement du code utilisateur." -#: src/grader/grading.ml:117,22--45 +#: File "src/grader/grading.ml", line 115, characters 22-45 msgid "Loading the solution." msgstr "Chargement de la solution." -#: src/grader/grading.ml:118,38--66 +#: File "src/grader/grading.ml", line 116, characters 38-66 msgid "while loading the solution" msgstr "lors du chargement de la solution" -#: src/grader/grading.ml:122,22--54 +#: File "src/grader/grading.ml", line 120, characters 22-54 msgid "Preparing to launch the tests." msgstr "Préparation du lancement des tests." -#: src/grader/grading.ml:144,22--49 +#: File "src/grader/grading.ml", line 142, characters 22-49 msgid "Launching the test bench." msgstr "Lancement du banc de test." -#: src/grader/grading.ml:145,38--67 -msgid "while testing your solution" -msgstr "lors du test de la solution utilisateur" - -#: src/grader/grading.ml:173,43--80 +#: File "src/grader/grading.ml", line 171, characters 45-78 msgid "while loading user dependencies" msgstr "lors du chargement des dépendances" -msgid "Failed to download archive. Please try again later!" -msgstr "" -"Le téléchargement de l'archive a échoué. Veuillez réessayer " -"ulterieurement!" +#: File "src/grader/grading.ml", line 187, characters 38-67 +msgid "while testing your solution" +msgstr "lors du test de la solution utilisateur" + +#~ msgid "Failed to download archive. Please try again later!" +#~ msgstr "" +#~ "Le téléchargement de l'archive a échoué. Veuillez réessayer " +#~ "ulterieurement!" #~ msgid "No description available." #~ msgstr "Aucune description." @@ -1034,4 +1026,3 @@ msgstr "" #~ msgid "This session has been closed. You can close this tab." #~ msgstr "La session a été fermée. Vous pouvez fermer cet onglet." -