diff --git a/src/trywhy3/editor_helper.js b/src/trywhy3/editor_helper.js new file mode 100644 index 0000000000000000000000000000000000000000..27ce2bb06d8ed8f4d7b1192ca65b759364dcb9ec --- /dev/null +++ b/src/trywhy3/editor_helper.js @@ -0,0 +1,202 @@ +/* Global objects */ +var editor = ace.edit("editor"); +editor.setTheme("ace/theme/chrome"); +editor.getSession().setMode("ace/mode/ocaml"); +var Range = ace.require("ace/range").Range; +var selectedRange = null; +var marker = null; +editor.$blockScrolling = Infinity; + +function highlightError (x1, y1, x2, y2) +{ + selectedRange = new Range (x1,y1,x2,y2); + marker = editor.session.addMarker(selectedRange, "error", "text"); +} + + +function clearHighlight () +{ + if (marker) { + editor.session.removeMarker(marker); + marker = null; + }; +} + +editor.on("change", clearHighlight); + +function moveToError () +{ + if (selectedRange) { + editor.selection.setSelectionRange(selectedRange); + editor.moveCursorToPosition(selectedRange.start); + selectedRange = null; + } +} + +editor.on("focus", moveToError); + + + +function clearConsole () +{ + document.getElementById("console").innerHTML = ""; + editor.focus(); +} + + +function openFile () +{ + document.getElementById("file-selector").click(); + editor.focus(); +} + + +var loadedBuffer = ""; +var loadedFilename = ""; +var currentFilename = ""; +var fileSelector = document.getElementById("file-selector"); + +function realReplaceBuffer() +{ + editor.setValue(loadedBuffer,-1); + currentFilename = loadedFilename; + //document.getElementById("filename_panel").innerHTML = loadedFilename; + loadedFilename = ""; + loadedBuffer = ""; +} + +function confirmReplace () +{ + realReplaceBuffer(); + document.getElementById("background-shadow").style.display = "none"; + document.getElementById("confirm-dialog").style.display = "none"; + editor.focus(); +} + +function cancelReplace () +{ + loadedBuffer = ""; + loadedFilename = ""; + document.getElementById("background-shadow").style.display = "none"; + document.getElementById("confirm-dialog").style.display = "none"; + editor.focus(); +} + + +function replaceWithLoaded() +{ + if (/\S/.test(editor.getValue())) { + document.getElementById("background-shadow").style.display = "block"; + document.getElementById("confirm-dialog").style.display = "block"; + } + else { + realReplaceBuffer(); + } + editor.focus(); +} + +function clearBuffer () +{ + loadedBuffer = ""; + loadedFilename = ""; + replaceWithLoaded(); +} + + +function realOpenFile (ev) +{ + var f = ev.target.files[0]; + if (f) { + var r = new FileReader(); + r.onload = function(e) { + loadedBuffer = e.target.result; + loadedFilename = f.name; + replaceWithLoaded(); + }; + r.readAsText(f); + }; + this.value = null; + editor.focus(); +} + +function drinkers(ev) +{ + loadedBuffer = "theory T\n\ +\n\ + (** Type of all persons *)\n\ + type person\n\ +\n\ + (** Predicate saying that some person drinks *)\n\ + predicate drinks person\n\ +\n\ + (** Paradox: there exists a person x such that\n\ + if x drinks, then everybody drinks *)\n\ + goal drinkers_paradox: \n\ + exists x:person. drinks x ->\n\ + forall y:person. drinks y\n\ +\n\ +end\n\ +"; + loadedFilename = "drinkers.why"; + replaceWithLoaded(); + editor.focus(); +} + +fileSelector.addEventListener("change", realOpenFile, false); + + +var saveFile = (function () +{ + var a = document.createElement ("a"); + document.body.appendChild(a); + a.style.height = "0"; + a.style.width = "0"; + a.style.position = "absolute"; + a.style.top = "0"; + a.style.left = "0"; + a.style.zIndex = "-10"; + return function () { + a.href = "data:application/octet-stream;base64," + btoa(editor.getValue()+"\n"); + a.download = /\S/.test(currentFilename) ? currentFilename : "Test.cd"; + a.click(); + editor.focus(); + }; +}) (); + + +function standardView() +{ + var e = document.getElementById("editor"); + var c = document.getElementById("console"); + e.style.width = "100%"; + e.style.height = "60vh"; + c.style.width = "100%"; + c.style.height = "37vh"; + editor.focus(); +} + +function widescreenView() +{ + var e = document.getElementById("editor"); + var c = document.getElementById("console"); + e.style.width = "50%"; + e.style.height = "100%"; + c.style.width = "40%"; + c.style.height = "100%"; + editor.focus(); +} + +function prove() +{ + document.getElementById("console").innerHTML = "

Execution feature is not yet implemented

"; + console.focus(); + editor.focus(); +} + +function prove() +{ + document.getElementById("console").innerHTML = "

Call to Why3 is not yet implemented

"; + editor.focus(); +} + +editor.focus(); diff --git a/src/trywhy3/index.html b/src/trywhy3/index.html index 9e551cfc0b8d588387a841ff77eb832a3411e5ed..da2aec558463cb2d4ff5fff98b87887bd4f069fb 100644 --- a/src/trywhy3/index.html +++ b/src/trywhy3/index.html @@ -1,26 +1,38 @@ - - + Try Why3 + + + -

Try Why3

-

Type some program in the text area below, then click on - button 'Go' on the left to run Why3 on it.

-

Click on the other buttons to select one of the proposed examples.

- - -
-
-
-
-
- + + +
+
+ The content of the current buffer will be lost.
+
+ + +
+
-
-
+ +

Try Why3

+

Type some program in the text area below, then select + 'Prove all' in the Why3 menu to generate proof obligations.

Related links

+ +
+
+
+
+
+ + + + diff --git a/src/trywhy3/style.css b/src/trywhy3/style.css new file mode 100644 index 0000000000000000000000000000000000000000..dba45f93e803c8ae8ed952531c29d013c4f1f579 --- /dev/null +++ b/src/trywhy3/style.css @@ -0,0 +1,182 @@ +body { + padding:0; + margin:0; + font-family: sans-serif; +} + +/* CSS MENU BAR */ + +.menu-bar { + margin:0; + z-index:10; + font-size:2vh; + padding:0; +} + +.menu-bar:after { + content:""; + display:table; + clear:both; +} + +.menu-bar ul { + padding:0; + margin:0; + list-style: none; + position: relative; + background-image: linear-gradient(to bottom, #eee, #ccc); + height:3vh; + z-index:10; + box-sizing:border-box; + } + +/* Positioning the navigation items inline */ +.menu-bar ul li { + margin: 0; + padding:0; + display:inline-block; + float: left; + height:100%; + box-sizing:border-box; +} + +/* Styling the links */ +.menu-bar > ul > li > a { + display:block; + padding:0pt 1em; + color:#444; + text-decoration:none; + border-radius: 5pt 5pt 0pt 0pt; + border-style:solid; + border-width:1pt; + border-color:transparent; + height:100%; + box-sizing:border-box; + margin:0; +} + +/* Background color change on Hover */ +.menu-bar > ul > li > a:hover { + background-image: linear-gradient(to bottom, #eee, #bbb); + border-color: #aaa; + box-sizing:border-box; + +} +.menu-bar > ul > li > ul { +/* display:none;*/ + height:0; + overflow:hidden; + box-sizing:border-box; + +} +.menu-bar > ul > li:hover > ul { + height:auto; + background-color:#ddd; + box-shadow:0pt 0pt 5pt #444; +} +.menu-bar > ul > li > ul > li { + float:none; + display:list-item; + position: relative; +} +.menu-bar > ul > li > ul > li > a { + display:block; + padding:1pt 2pt 1pt 2pt; + color:#444; + text-decoration:none; + border-radius: 1pt; + border-style:solid; + border-width:1pt; + border-color:transparent; + box-sizing:border-box; + +} +.menu-bar > ul > li > ul > li > a:hover { + border-color:#cce; + background-image: linear-gradient(to bottom, #abe, #68b); +} + +/* Hidden file selector */ +#file-selector { + position:absolute; + left:0; + top:0; + width:0; + height:0; + z-index:-1; +} + +#editor-panel { + position:relative; + display:block; + box-sizing: border-box; + padding:0; + margin:0; + height:97vh; +} + +#console { + position:relative; + display:inline-block; + box-sizing: border-box; + font-size: large; + font-family: monospace; + white-space: pre-wrap; + width:40%; + height:100%; +/* background: #444; */ + margin:0 0 0 0; + padding:0 0 0 0; + vertical-align:top; +} + +#editor { + position:relative; + font-size: large; + box-sizing: border-box; + display:inline-block; + width:50%; + height:100%; + margin:0 0 0 0; + padding:0 0 0 0; + z-index:0; + vertical-align:top; +} + +/* Confirmation dialog */ +.btn { + width:100%; + z-index:1; + margin:0 0 4pt 0; + box-sizing:border-box; +} + +#confirm-dialog { + z-index:20; + display:none; + position:absolute; + margin: 0 auto; + padding: 2pt 0; + width:50%; + left:25%; + right:25%; + top:20%; + border-radius:5pt; + background: #eee; + text-align:center; +} + +#background-shadow { + display:none; + background-color: rgba(0,0,0,0.8); + position:absolute; + width:100%; + height:100%; + top: 0; + left:0; + z-index:15; +} + +#confirm-dialog .btn { + width:40%; +} diff --git a/src/trywhy3/trywhy3.ml b/src/trywhy3/trywhy3.ml index 5da9d32818120783d95af14dbadf079f60fe1b36..c5e2840726d4c8b59273a2d4ff18987aea16ba3b 100644 --- a/src/trywhy3/trywhy3.ml +++ b/src/trywhy3/trywhy3.ml @@ -1,74 +1,5 @@ - -let examples = - [ "Drinkers paradox"," -theory T - - (** Type of all persons *) - type person - - (** Predicate saying that some person drinks *) - predicate drinks person - - (** Paradox: there exists a person x such that if x drinks, - then everybody drinks *) - goal drinkers_paradox: exists x:person. drinks x -> forall y:person. drinks y - -end -"; - "Simple Arithmetic"," -theory T - - use import int.Int - - goal g: exists x:int. x*(x+1) = 42 - -end -"; -"Integral square root"," -module M - - use import int.Int - use import ref.Ref - - function sqr (x:int) : int = x * x - - let isqrt (x:int) : int - requires { x >= 0 } - ensures { result >= 0 } - ensures { result <= x < sqr (result + 1) } - = let count = ref 0 in - let sum = ref 1 in - while !sum <= x do - invariant { !count >= 0 } - invariant { x >= sqr !count } - invariant { !sum = sqr (!count+1) } - variant { x - !count } - count := !count + 1; - sum := !sum + 2 * !count + 1 - done; - !count - - let main () ensures { result = 4 } = isqrt 17 - -end -"; - ] - -(** registering the std lib *) - -(* -let () = - List.iter - (fun (name,content) -> - Sys_js.register_file ~name ~content; - ) Theories.theories -*) - - -(** Rendering in the browser *) - module D = Dom_html module Html = struct @@ -96,6 +27,13 @@ let ul nl = end +let get_opt o = + Js.Opt.get o (fun () -> assert false) + +let log s = + Firebug.console ## log (Js.string s) + + let temp_file_name = "/input.mlw" let why3_conf_file = "/why3.conf" @@ -140,141 +78,115 @@ let run_alt_ergo_on_task t = Driver.print_task alt_ergo_driver str_formatter t; let text = flush_str_formatter () in (* TODO ! *) +(* from Alt-Ergo: + let a = Why_parser.file Why_lexer.token lb in + let ltd, typ_env = Why_typing.file false Why_typing.empty_env a in + let declss = Why_typing.split_goals ltd in + SAT.start (); + let declss = List.map (List.map fst) declss in + let report = FE.print_status in + let pruning = + List.map + (fun d -> + if select () > 0 then Pruning.split_and_prune (select ()) d + else [List.map (fun f -> f,true) d]) + in + List.iter + (List.iter + (fun dcl -> + let cnf = Cnf.make dcl in + ignore (Queue.fold (FE.process_decl report) + (SAT.empty (), true, Explanation.empty) cnf) + )) (pruning declss) +*) text let split_trans = Trans.lookup_transform_l "split_goal_wp" env -let run textbox preview (_ : D.mouseEvent Js.t) : bool Js.t = - let text = Js.to_string (textbox##value) in +let prove text = let ch = open_out temp_file_name in output_string ch text; close_out ch; - let answer = - try - (* TODO: add a function Env.read_string or Env.read_from_lexbuf ? *) - let theories = Env.read_file Env.base_language env temp_file_name in -(* - Html.par - [Html.of_string - (Pp.sprintf "parsing and typing OK, %d theories" - (Stdlib.Mstr.cardinal theories))] -*) - let theories = - Stdlib.Mstr.fold - (fun thname th acc -> - let tasks = Task.split_theory th None None in - let tasks = List.map - (fun t -> - let (id,expl,_) = Termcode.goal_expl_task ~root:true t in - let expl = match expl with - | Some s -> s - | None -> id.Ident.id_string - in - let tl = Trans.apply split_trans t in - let tasks = - List.map - (fun task -> - let (id,expl,_) = Termcode.goal_expl_task ~root:false task in - let expl = match expl with - | Some s -> s - | None -> id.Ident.id_string - in - let result = run_alt_ergo_on_task task in - let result = - if String.length result > 80 then - "..." ^ String.sub result (String.length result - 80) 80 - else result - in - [Html.of_string (expl ^" : " ^ result)]) - tl - in - [Html.of_string expl; Html.ul tasks]) - tasks - in - [ Html.of_string ("Theory " ^ thname); Html.ul tasks] - :: acc) - theories [] - in - Html.ul theories -(* - Stdlib.Mstr.iter - (fun _thname th -> + try + (* TODO: add a function Env.read_string or Env.read_from_lexbuf ? *) + let theories = Env.read_file Env.base_language env temp_file_name in + let theories = + Stdlib.Mstr.fold + (fun thname th acc -> let tasks = Task.split_theory th None None in - List.iter - (fun task -> - let (id,expl,_) = Termcode.goal_expl_task ~root:true task in + let tasks = List.map + (fun t -> + let (id,expl,_) = Termcode.goal_expl_task ~root:true t in let expl = match expl with | Some s -> s | None -> id.Ident.id_string in - push_answer - (Pp.sprintf "Goal: %s@\n" expl)) - tasks) -*) - with - | Loc.Located(loc,Parser.Error) -> - let (_,l,b,e) = Loc.get loc in - Html.par - [Html.of_string - (Pp.sprintf "syntax error line %d, columns %d-%d" l b e)] - | Loc.Located(loc,e') -> - let (_,l,b,e) = Loc.get loc in - Html.par - [Html.of_string - (Pp.sprintf - "error line %d, columns %d-%d: %a" l b e - Exn_printer.exn_printer e')] - | e -> - Html.par - [Html.of_string - (Pp.sprintf - "unexpected exception: %a (%s)" Exn_printer.exn_printer e - (Printexc.to_string e))] + let tl = Trans.apply split_trans t in + let tasks = + List.map + (fun task -> + let (id,expl,_) = Termcode.goal_expl_task ~root:false task in + let expl = match expl with + | Some s -> s + | None -> id.Ident.id_string + in + let result = run_alt_ergo_on_task task in + let result = + if String.length result > 80 then + "..." ^ String.sub result (String.length result - 80) 80 + else result + in + [Html.of_string (expl ^" : " ^ result)]) + tl + in + [Html.of_string expl; Html.ul tasks]) + tasks + in + [ Html.of_string ("Theory " ^ thname); Html.ul tasks] + :: acc) + theories [] + in + Html.ul theories + with + | Loc.Located(loc,Parser.Error) -> + let (_,l,b,e) = Loc.get loc in + Html.par + [Html.of_string + (Pp.sprintf "syntax error line %d, columns %d-%d" l b e)] + | Loc.Located(loc,e') -> + let (_,l,b,e) = Loc.get loc in + Html.par + [Html.of_string + (Pp.sprintf + "error line %d, columns %d-%d: %a" l b e + Exn_printer.exn_printer e')] + | e -> + Html.par + [Html.of_string + (Pp.sprintf + "unexpected exception: %a (%s)" Exn_printer.exn_printer e + (Printexc.to_string e))] +let () = + let handler = Dom.handler + (fun _ev -> + log "why3 prove is running"; + let global = Js.Unsafe.global in + let editor = Js.Unsafe.get global (Js.string "editor") in + let code = Js.to_string (Js.Unsafe.meth_call editor "getValue" [| |]) in + let answer = prove code in + (* remove the previous answer if any *) + let console = + get_opt (Dom_html.document ## getElementById (Js.string "console")) + in + Js.Opt.iter (console##lastChild) (Dom.removeChild console); + (* put the new answer *) + Dom.appendChild console answer; + Js._false) in - (* remove the previous answer if any *) - Js.Opt.iter (preview##lastChild) (Dom.removeChild preview); - (* put the new answer *) - Dom.appendChild preview answer; - Js._false - -let onload (_event : #Dom_html.event Js.t) : bool Js.t = - let input = - Js.Opt.get (Html.d##getElementById(Js.string "input")) - (fun () -> assert false) in - let output = - Js.Opt.get (Html.d##getElementById(Js.string "output")) - (fun () -> assert false) in - (* first, the textbox *) - let textbox = D.createTextarea Html.d in - textbox##rows <- 32; textbox##cols <- 64; - Dom.appendChild input textbox; - (* second, the example buttons *) - List.iter - (fun (name,text) -> - let b = D.createButton ~name:(Js.string name) Html.d in - b##textContent <- Js.some (Js.string name); - Dom.appendChild output b; - b##onclick <- - D.handler - (fun (_ : D.mouseEvent Js.t) -> - textbox##value <- Js.string text; - Js._false)) - examples; - Dom.appendChild output (D.createBr Html.d); - (* third, the go button *) - let go = D.createButton ~name:(Js.string "go") Html.d in - go##textContent <- Js.some (Js.string "Go"); - Dom.appendChild output go; - Dom.appendChild output (D.createBr Html.d); - (* then, the answer zone *) - let preview = D.createDiv Html.d in - go##onclick <- D.handler (run textbox preview); - preview##style##border <- Js.string "1px black"; - preview##style##padding <- Js.string "5px"; - Dom.appendChild output preview; - Js._false - -let _ = D.window##onload <- D.handler onload + let button = + get_opt (Dom_html.document ## getElementById (Js.string "prove")) + in + button ## onclick <- handler (*