diff --git a/assets/css/browser-solidity.css b/assets/css/browser-solidity.css
index b6b31f0cf8..1e3f5d4ca0 100644
--- a/assets/css/browser-solidity.css
+++ b/assets/css/browser-solidity.css
@@ -209,6 +209,7 @@ body {
#header #optionViews.publishView #publishView { display: block; }
#header #optionViews.envView #envView { display: block; }
#header #optionViews.debugView #debugView { display: block; }
+#header #optionViews.verificationView #verificationView { display: block; }
#header #optionViews.txView input,
#header #optionViews.txView select {
@@ -273,6 +274,11 @@ body {
float: left;
}
+#formalVerificationInput {
+ height: 4.5em;
+ width: 100%;
+}
+
.contract.hide {
padding-bottom: 0;
}
diff --git a/index.html b/index.html
index ce27d99a5e..ed660a6058 100644
--- a/index.html
+++ b/index.html
@@ -65,6 +65,7 @@
+
@@ -125,6 +126,19 @@
+
+
This tab provides support for formal verification of Solidity contracts.
+ This feature is still in development and thus also not yet well documented,
+ but you can find some information
+ here.
+ The compiler generates input to be verified
+ (or report errors). Please paste the text below into
+ http://why3.lri.fr/try/
+ to actually perform the verification.
+ We plan to support direct integration in the future.
+
+
+
diff --git a/src/app.js b/src/app.js
index ec0adc90b5..d19d2e8a0c 100644
--- a/src/app.js
+++ b/src/app.js
@@ -14,6 +14,7 @@ var Renderer = require('./app/renderer');
var Compiler = require('./app/compiler');
var ExecutionContext = require('./app/execution-context');
var Debugger = require('./app/debugger');
+var FormalVerification = require('./app/formalVerification');
// The event listener needs to be registered as early as possible, because the
// parent will send the message upon the "load" event.
@@ -437,7 +438,8 @@ var run = function () {
selectTab($('ul#options li.debugView'));
};
var renderer = new Renderer(editor, executionContext, updateFiles, transactionDebugger);
- var compiler = new Compiler(editor, renderer, queryParams, handleGithubCall, $('#output'), getHidingRHP, updateFiles);
+ var formalVerification = new FormalVerification($('#verificationView'), renderer);
+ var compiler = new Compiler(editor, renderer, queryParams, handleGithubCall, $('#output'), getHidingRHP, formalVerification, updateFiles);
executionContext.setCompiler(compiler);
function setVersionText (text) {
diff --git a/src/app/compiler.js b/src/app/compiler.js
index 80024e9b6f..cd6cf7d3ee 100644
--- a/src/app/compiler.js
+++ b/src/app/compiler.js
@@ -5,7 +5,7 @@ var utils = require('./utils');
var Base64 = require('js-base64').Base64;
-function Compiler (editor, renderer, queryParams, handleGithubCall, outputField, hidingRHP, updateFiles) {
+function Compiler (editor, renderer, queryParams, handleGithubCall, outputField, hidingRHP, formalVerification, updateFiles) {
var compileJSON;
var compilerAcceptsMultipleFiles;
@@ -37,6 +37,9 @@ function Compiler (editor, renderer, queryParams, handleGithubCall, outputField,
var compile = function (missingInputs) {
editor.clearAnnotations();
outputField.empty();
+ if (formalVerification) {
+ formalVerification.compiling();
+ }
var input = editor.getValue();
editor.setCacheFileContent(input);
@@ -114,6 +117,7 @@ function Compiler (editor, renderer, queryParams, handleGithubCall, outputField,
compile(missingInputs);
} else if (noFatalErrors && !hidingRHP()) {
renderer.contracts(data, editor.getValue());
+ formalVerification.compilationFinished(data);
}
}
diff --git a/src/app/formalVerification.js b/src/app/formalVerification.js
new file mode 100644
index 0000000000..c69ab863c1
--- /dev/null
+++ b/src/app/formalVerification.js
@@ -0,0 +1,39 @@
+var $ = require('jquery');
+
+function FormalVerification (outputElement, renderer) {
+ this.outputElement = outputElement;
+ this.renderer = renderer;
+}
+
+FormalVerification.prototype.compiling = function () {
+ $('#formalVerificationInput', this.outputElement)
+ .val('')
+ .hide();
+ $('#formalVerificationErrors').empty();
+};
+
+FormalVerification.prototype.compilationFinished = function (compilationResult) {
+ if (compilationResult.formal === undefined) {
+ this.renderer.error(
+ 'Formal verification not supported by this compiler version.',
+ $('#formalVerificationErrors'),
+ true
+ );
+ } else {
+ if (compilationResult.formal['why3'] !== undefined) {
+ $('#formalVerificationInput', this.outputElement).val(
+ '(* copy this to http://why3.lri.fr/try/ *)' +
+ compilationResult.formal['why3']
+ )
+ .show();
+ }
+ if (compilationResult.formal.errors !== undefined) {
+ var errors = compilationResult.formal.errors;
+ for (var i = 0; i < errors.length; i++) {
+ this.renderer.error(errors[i], $('#formalVerificationErrors'), true);
+ }
+ }
+ }
+};
+
+module.exports = FormalVerification;
diff --git a/src/app/renderer.js b/src/app/renderer.js
index c82e7551db..808a347590 100644
--- a/src/app/renderer.js
+++ b/src/app/renderer.js
@@ -7,17 +7,20 @@ var utils = require('./utils');
function Renderer (editor, executionContext, updateFiles, transactionDebugger) {
var detailsOpen = {};
- function renderError (message) {
+ function renderError (message, container, noAnnotations) {
var type = utils.errortype(message);
var $pre = $('').text(message);
var $error = $('').prepend($pre);
- $('#output').append($error);
+ if (container === undefined) {
+ container = $('#output');
+ }
+ container.append($error);
var err = message.match(/^([^:]*):([0-9]*):(([0-9]*):)? /);
if (err) {
var errFile = err[1];
var errLine = parseInt(err[2], 10) - 1;
var errCol = err[4] ? parseInt(err[4], 10) : 0;
- if (errFile === '' || errFile === utils.fileNameFromKey(editor.getCacheFile())) {
+ if (!noAnnotations && (errFile === '' || errFile === utils.fileNameFromKey(editor.getCacheFile()))) {
editor.addAnnotation({
row: errLine,
column: errCol,