Commit fbf98a85 authored by Louis Gesbert's avatar Louis Gesbert
Browse files

foo

parent 4d1e2859
let () = prerr_endline (greetings ^ "1")
let prepared = "prepared "^greetings
let () = print_endline prepared
let plus = (+)
let plus_tests = [((1, 1), 2)]
......
(* auto-inserted !! *)
open Pre_test
module Test_lib = Test_lib.Make(struct
let results = results
let set_progress = set_progress
let timeout = timeout
module Introspection = Introspection
end)
module Report = Learnocaml_report
module Introspection = Introspection
(* open Pre_test
* module Test_lib = Test_lib.Make(struct
* let results = results
* let set_progress = set_progress
* let timeout = timeout
* module Introspection = Introspection
* end)
* module Report = Learnocaml_report
* module Introspection = Introspection *)
(* test.ml start *)
......
The following example link will open another tab/window: [OCaml](https://ocaml.org "External link")
This exercise is just another demo for the exercise environment.
<a href="" onclick="top.location='/exercises/demo/';">Test</a>
<details>
<summary>Hint</summary>
Use an indirection.
</details>
{"learnocaml_version":"1","kind":"exercise","stars":0,
"title":"Demo of the exercise environment (MD version)"}
(* Some code is loaded in the toplevel before your code. *)
let greetings = "Hello world!"
let plus = (+)
let times = ( * )
let minus = ( - )
let divide = ( / )
let plus x y = x + y ;;
let minus x y = y - x ;;
let times x y = x *
open Test_lib
open Report
let () =
set_result @@
ast_sanity_check code_ast @@ fun () ->
[ Section
([ Text "Function:" ; Code "plus" ],
test_function_2_against_solution
[%ty : int -> int -> int ] "plus"
[ (1, 1) ; (2, 2) ; (10, -10) ]) ;
Section
([ Text "Function:" ; Code "minus" ],
test_function_2_against_solution
[%ty : int -> int -> int ] "minus"
[ (1, 1) ; (4, -2) ; (0, 10) ]) ;
Section
([ Text "Function:" ; Code "times" ],
test_function_2_against_solution
[%ty : int -> int -> int ] "times"
[ (1, 3) ; (2, 4) ; (3, 0) ]) ;
Section
([ Text "Function:" ; Code "divide" ],
test_function_2_against_solution
[%ty : int -> int -> int ] "divide"
[ (12, 4) ; (12, 5) ; (3, 0) ]) ]
......@@ -2,4 +2,4 @@
"groups":
{ "demo":
{ "title": "Demo exercise pack",
"exercises": [ "demo", "demo2" ] } } }
"exercises": [ "demo" ] } } }
......@@ -7,7 +7,7 @@
)
(env
(release (flags -safe-string -w +a-4-42-44-45-48-3-58)
(release (flags -safe-string -w +a-4-42-44-45-48-3-58-32-33)
(ocamlc_flags)
(ocamlopt_flags))
)
(lang dune 2.3)
(lang dune 2.4)
(name learn-ocaml)
(version 0.13.2)
(allow_approximate_merlin)
......@@ -71,7 +71,7 @@ let () =
init_tabs ();
exercise_fetch >>= fun (ex_meta, exo, _deadline) ->
(* display exercise questions and prelude *)
setup_tab_text_prelude_pane Learnocaml_exercise.(decipher File.prelude exo);
setup_tab_text_prelude_pane Learnocaml_exercise.(decipher File.prelude_ml exo);
let text_iframe = Dom_html.createIframe Dom_html.document in
Manip.replaceChildren title_container
Tyxml_js.Html5.[ h1 [ txt ex_meta.title] ];
......
......@@ -123,16 +123,24 @@ let () =
in
let after_init top =
exercise_fetch >>= fun (_meta, exo, _deadline) ->
begin match Learnocaml_exercise.(decipher File.prelude exo) with
| "" -> Lwt.return true
| prelude ->
Learnocaml_toplevel.load ~print_outcome:true top
~message: [%i"loading the prelude..."]
prelude
end >>= fun r1 ->
Learnocaml_toplevel.load ~print_outcome:false top
(Learnocaml_exercise.(decipher File.prepare exo)) >>= fun r2 ->
if not r1 || not r2 then failwith [%i"error in prelude"] ;
let exercise_js = Learnocaml_exercise.(decipher File.exercise_js exo) in
Learnocaml_toplevel.load_cmi_from_string top
Learnocaml_exercise.(decipher File.prelude_cmi exo) >>= fun _ ->
Learnocaml_toplevel.load_cmi_from_string top
Learnocaml_exercise.(decipher File.prepare_cmi exo) >>= fun _ ->
(* Toploop_ext.load_cmi_from_string
* Learnocaml_exercise.(decipher File.prepare_cmi exo); (\* FIXME was this present ?? *\) *)
Learnocaml_toplevel.load_js ~print_outcome:true top
(* FIXME: loading the prelude used to have print_outcome=true *)
~message: [%i"loading the prelude..."]
exercise_js
>>= fun r ->
if not r then (* failwith [%i"error in prelude"] *) debug "FAILED TO LOAD PRELUDE (1)";
Learnocaml_toplevel.load top "open! Prelude ;;" >>= fun r ->
if not r then (* failwith [%i"error in prelude"] *) debug "FAILED TO LOAD PRELUDE (2)";
Learnocaml_toplevel.load top "include Prepare ;;" >>= fun r ->
if not r then (* failwith [%i"error in prelude"] *) debug "FAILED TO LOAD PRELUDE (3)";
(* FIXME: remove Prelude, Prepare modules from the env ? *)
Learnocaml_toplevel.set_checking_environment top >>= fun () ->
Lwt.return () in
let toplevel_launch =
......@@ -188,7 +196,7 @@ let () =
EB.eval top select_tab;
let typecheck = typecheck top ace editor in
(*------------- prelude -----------------*)
setup_prelude_pane ace Learnocaml_exercise.(decipher File.prelude exo);
setup_prelude_pane ace Learnocaml_exercise.(decipher File.prelude_ml exo);
Js.Opt.case
(text_iframe##.contentDocument)
(fun () -> failwith "cannot edit iframe document")
......
......@@ -13,8 +13,30 @@
(action (run odoc compile --package learn-ocaml %{deps} -o %{targets}))
)
;; needs to be a separate lib because the module is shared between evaluator
;; parts (Grading) and dynamic parts (Test_lib)
(library
(name testing)
(name introspection_intf)
(wrapped false)
(modules introspection_intf)
(modules_without_implementation introspection_intf)
(libraries learnocaml_report ty))
;; dynamic part, on which Test_lib depends
(library
(name pre_test)
(wrapped false)
(modules pre_test)
(modules_without_implementation pre_test)
;; hack: pre_test actually does have an implementation, but it is dynamically
;; generated and injected in the environment during grading. We are interested
;; in pre_test.cmi to compile test_lib.cmo, then test_lib.cmo should only be
;; loaded in the specific grading toplevel env.
(libraries compiler-libs learnocaml_report introspection_intf))
;; dynamic (but pre-compiled) part
(library
(name testing_dyn)
(wrapped false)
(modes byte)
(library_flags :standard -linkall)
......@@ -24,18 +46,21 @@
learnocaml_ppx_metaquot_lib
ocplib-json-typed
learnocaml_report
learnocaml_repository)
(modules Introspection_intf
Introspection
Test_lib
Mutation_test)
(modules_without_implementation Introspection_intf)
learnocaml_repository
introspection_intf
pre_test ;; dynamic dependency
)
(modules Test_lib Mutation_test)
(preprocess (pps learnocaml_ppx_metaquot))
)
(rule
(target testing_dyn.js)
(deps testing_dyn.cma)
(action (run js_of_ocaml %{deps})))
(rule
(targets test_lib.odoc)
(deps .testing.objs/byte/test_lib.cmti)
(deps .testing_dyn.objs/byte/test_lib.cmti)
(action (run odoc compile --package learn-ocaml %{deps} -o %{targets}))
)
......@@ -46,8 +71,6 @@
(run odoc html %{dep:test_lib.odoc} -o %{workspace_root}/_doc/_html)))
)
(rule
(targets embedded_cmis.ml)
(deps
......@@ -115,8 +138,8 @@
%{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)
../toplevel/.learnocaml_toplevel_pp.objs/byte/learnocaml_toplevel_pp.cmi
../grader/.pre_test.objs/byte/pre_test.cmi)
(:lib_cmis
%{lib:re:re.cmi}
%{lib:gg:gg.cmi}
......@@ -151,10 +174,14 @@
(:generated-cmis
../ppx-metaquot/.ty.objs/byte/ty.cmi
../ppx-metaquot/.fun_ty.objs/byte/fun_ty.cmi
.testing.objs/byte/introspection_intf.cmi
.introspection_intf.objs/byte/introspection_intf.cmi
.pre_test.objs/byte/pre_test.cmi
.learnocaml_report.objs/byte/learnocaml_report.cmi
.testing.objs/byte/test_lib.cmi
.testing.objs/byte/mutation_test.cmi))
.testing_dyn.objs/byte/test_lib.cmi
.testing_dyn.objs/byte/mutation_test.cmi
testing_dyn.cma ;; Alright the lib name is no longer adequate
testing_dyn.js
))
(action (with-stdout-to %{targets}
(run ocp-ocamlres -format ocamlres %{compiler-cmis} %{generated-cmis})))
)
......@@ -164,13 +191,16 @@
(wrapped false)
(modes byte)
(library_flags :standard -linkall)
(libraries testing
learnocaml_ppx_metaquot
(libraries learnocaml_ppx_metaquot
ocplib-ocamlres.runtime
toploop
introspection_intf
embedded_cmis
ocplib_i18n
learnocaml_report)
(modules Embedded_grading_cmis
learnocaml_report
learnocaml_repository)
(modules Introspection
Embedded_grading_cmis
Grading)
(preprocess (per_module ((pps ppx_ocplib_i18n learnocaml_ppx_metaquot) Grading)))
)
......
......@@ -53,7 +53,8 @@ let grade ?(print_result=false) ?dirname meta exercise output_json =
let code_to_grade = match !grade_student with
| Some path -> read_student_file (Sys.getcwd ()) path
| None ->
Lwt.return (Learnocaml_exercise.(decipher File.solution exercise)) in
read_student_file Learnocaml_exercise.("demo-repository/exercises/" ^ decipher File.id exercise) "solution.ml" (* FIXME *)
(* Lwt.return (Learnocaml_exercise.(decipher File.solution exercise)) *) in
let callback =
if !display_callback then Some (Printf.eprintf "[ %s ]%!\r\027[K") else None in
let timeout = !individual_timeout in
......
......@@ -34,10 +34,10 @@ let get_grade ?callback exo solution =
let divert name chan cb =
let redirection = Toploop_jsoo.redirect_channel name chan cb in
fun () -> Toploop_jsoo.stop_channel_redirection redirection in
let load_code js_code =
let load_code compiled_code =
prerr_endline ("USE_JS_STRING");
try
Toploop_jsoo.use_compiled_string js_code;
Toploop_jsoo.use_compiled_string compiled_code.Learnocaml_exercise.js;
flush_all ();
Toploop_ext.Ok (true, [])
with exn ->
......
......@@ -41,6 +41,7 @@ let user_code_error err =
let get_grade
?callback ?timeout ?(dirname="") ~divert ~load_code
(exo : Learnocaml_exercise.t) code =
prerr_endline "GET_GRADE";
let file f = String.concat Filename.dir_sep [dirname; f] in
......@@ -93,60 +94,82 @@ let get_grade
fail err in
let result = try
handle_error (internal_error [%i"while preparing the tests"]) @@
handle_error (internal_error [%i"while preparing the tests (1)"]) @@
Toploop_ext.use_string ~print_outcome ~ppf_answer
{|let print_html _ = assert false|};
set_progress [%i"Loading the prelude."] ;
handle_error (internal_error [%i"while loading the prelude"]) @@
Toploop_ext.use_string ~print_outcome ~ppf_answer ~filename:(file "prelude.ml")
(Learnocaml_exercise.(decipher File.prelude exo)) ;
set_progress [%i"Preparing the test environment."] ;
handle_error (internal_error [%i"while preparing the tests"]) @@
load_code (Learnocaml_exercise.(decipher File.prepare exo)) ;
Toploop_ext.load_cmi_from_string (Learnocaml_exercise.(decipher File.prelude_cmi exo)) ;
Toploop_ext.load_cmi_from_string (Learnocaml_exercise.(decipher File.prepare_cmi exo)) ;
handle_error (internal_error [%i"while preparing the tests (2)"]) @@
load_code Learnocaml_exercise.{
cma = decipher File.exercise_cma exo ;
js = decipher File.exercise_js exo ;
};
handle_error (internal_error [%i"while preparing the tests (3)"]) @@
Toploop_ext.use_string ~print_outcome ~ppf_answer {|open! Prepare|};
prerr_endline "XX0";
set_progress [%i"Loading your code."] ;
handle_error user_code_error @@
Toploop_ext.use_mod_string ~print_outcome ~ppf_answer ~modname:"Code"
~filename:(file "solution.ml") code ;
set_progress [%i"Loading the solution."] ;
handle_error (internal_error [%i"while loading the solution"]) @@
load_code (* FIXME use_js_mod_string *)
(Learnocaml_exercise.(decipher File.solution exo)) ;
Toploop_ext.load_cmi_from_string (Learnocaml_exercise.(decipher File.solution_cmi exo)) ;
set_progress [%i"Preparing to launch the tests."] ;
Introspection.allow_introspection ~divert ;
Introspection.insert_mod_ast_in_env ~var_name: "code_ast" code ;
let get_result =
Introspection.create_ref "results"
[%ty: Learnocaml_report.t option]
None in
Introspection.register_callback "set_progress"
[%ty: string]
set_progress ;
Introspection.insert_in_env "timeout" [%ty: int option] timeout ;
handle_error (internal_error [%i"while preparing the tests"]) @@
Toploop_ext.use_string ~print_outcome ~ppf_answer
"module Test_lib = Test_lib.Make(struct\n\
\ let results = results\n\
\ let set_progress = set_progress\n\
\ let timeout = timeout\n\
\ module Introspection = Introspection\n\
end)" ;
handle_error (internal_error [%i"while preparing the tests"]) @@
Toploop_ext.use_string ~print_outcome ~ppf_answer
"module Report = Learnocaml_report" ;
(* The following 3 lines are just a workaround for issue #457 *)
handle_error (internal_error [%i"while preparing the tests"]) @@
Toploop_ext.use_string ~print_outcome ~ppf_answer
"module Introspection = Introspection" ;
set_progress [%i"Launching the test bench."] ;
let module Intro_inner = (val Introspection.allow_introspection ~divert) in
prerr_endline "XX1";
let code_ast = Introspection.get_mod_ast ~var_name:"code_ast" code in
prerr_endline "XX2";
let results: Learnocaml_report.t option ref = ref None in
let get_result () = !results in
let () =
let module Pre_test: Introspection_intf.PRE_TEST = struct
module Introspection = Intro_inner
let code_ast = code_ast
let results = results
let set_progress = set_progress
let timeout = timeout
end in
prerr_endline "XX3";
(* Toploop_ext.load_cmi_from_string OCamlRes.(Res.find (Path.of_string "pre_test.cmi")
* Embedded_grading_cmis.root) ; FIXME: load here and not from loadpath *)
(* Hack: register Pre_test as a compilation unit usable by the compiled
modules loaded later-on *)
Introspection.inject_global "Pre_test"
(Obj.repr (module Pre_test: Introspection_intf.PRE_TEST));
prerr_endline "XX3b";
(* Symtable.update_global_table () *)
(* Introspection.insert_in_env "Pre_test"
* [%ty: (module Introspection_intf.PRE_TEST)]
* (module Pre_test: Introspection_intf.PRE_TEST); *)
in
prerr_endline "XX4";
handle_error (internal_error [%i"while preparing the tests (4)"]) @@
load_code
{ Learnocaml_exercise.
cma = OCamlRes.(Res.find (Path.of_string "testing_dyn.cma")
Embedded_grading_cmis.root) ;
js = OCamlRes.(Res.find (Path.of_string "testing_dyn.js")
Embedded_grading_cmis.root) };
(* handle_error (internal_error [%i"while preparing the tests (5)"]) @@
* Toploop_ext.use_string ~print_outcome ~ppf_answer
* "module Report = Learnocaml_report" ; *)
(* (\* The following 3 lines are just a workaround for issue #457 *\)
* handle_error (internal_error [%i"while preparing the tests (6)"]) @@
* Toploop_ext.use_string ~print_outcome ~ppf_answer
* "module Introspection = Introspection" ; *)
prerr_endline "XX5";
(* FIXME: reimplement "depend.txt" support [{
let () =
let open Learnocaml_exercise in
let files = File.dependencies (access File.depend exo) in
if files <> [] then set_progress [%i"Loading test bench dependencies."] ;
let rec load_dependencies signatures = function
| [] -> () (* signatures without implementation are ignored *)
| file::fs ->
......@@ -186,11 +209,19 @@ let get_grade
"\", file extension expected : .ml or .mli") in
load_dependencies [] files
in
}] *)
handle_error (internal_error [%i"while preparing the tests (3)"]) @@
Toploop_ext.use_string ~print_outcome ~ppf_answer {|open! Test_lib|};
prerr_endline "XX0";
prerr_endline "XX6";
handle_error (internal_error [%i"while testing your solution"]) @@
Toploop_ext.use_string ~print_outcome ~ppf_answer ~filename:(file "test.ml")
(Learnocaml_exercise.(decipher File.test exo)) ;
load_code Learnocaml_exercise.{
cma = decipher File.test_cma exo ;
js = decipher File.test_js exo ;
};
prerr_endline "XX6";
(* Memory cleanup... *)
Toploop.initialize_toplevel_env () ;
(* TODO: Also clear the object table, once the OCaml's Toploop allows to. *)
......
......@@ -23,7 +23,7 @@ val get_grade:
?timeout:int ->
?dirname:string ->
divert:(string -> out_channel -> (string -> unit) -> (unit -> unit)) ->
load_code:(string -> bool Toploop_ext.toplevel_result) ->
load_code:(Learnocaml_exercise.compiled_lib -> bool Toploop_ext.toplevel_result) ->
Learnocaml_exercise.t -> string -> (Learnocaml_report.t, exn) result * string * string * string
(** Returns user-friendly messages when called on [Internal_error] or
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment