diff --git a/src/extension/html/_verify.single.html b/src/extension/html/_verify.single.html index 476acb8..0a65769 100644 --- a/src/extension/html/_verify.single.html +++ b/src/extension/html/_verify.single.html @@ -4,6 +4,7 @@

{%= spec %} {% } else { %} ❔ {% } %}

+{% if (tbody) { %} # @@ -13,6 +14,7 @@

{%= spec %} {%- tbody %} +{% } %}
diff --git a/src/extension/html/verify.html b/src/extension/html/verify.html index d380925..98e40bf 100644 --- a/src/extension/html/verify.html +++ b/src/extension/html/verify.html @@ -3,12 +3,13 @@ - R-CHECK: Verification of {%= fname %} (IC3) + R-CHECK: Verification of {%= fname %} ({%= subtitle %}) -

R-CHECK: Verification of {%= fname %} (IC3)

+

R-CHECK: Verification of {%= fname %}

+

{%= subtitle %}

{% if (body != undefined) { %}{%- body %} {% } else { %}{% } %} diff --git a/src/extension/verify.ts b/src/extension/verify.ts index 9abf06d..55cc1fe 100644 --- a/src/extension/verify.ts +++ b/src/extension/verify.ts @@ -28,13 +28,13 @@ export class Verify { const rcpPath = getCurrentRcpFile()!; const tmpJson = await temp.toJson(rcpPath); check() - .then(() => runJar(["-j", tmpJson, "--smv", "-tmp"])) - .then(findSpecs) - .then(value => verifySpecsIc3(rcpPath, tmpJson, value)) - .catch(vscode.window.showErrorMessage) + .then(() => runJar(["-j", tmpJson, "--smv", "-tmp"])) + .then(findSpecs) + .then(value => verifySpecsIc3(rcpPath, tmpJson, value)) + .catch(vscode.window.showErrorMessage) }), vscode.commands.registerCommand('rcheck.verify-bmc', async () => { - + const rcpPath = getCurrentRcpFile()!; const tmpJson = await temp.toJson(rcpPath); const boundString = await vscode.window.showInputBox({ @@ -45,23 +45,23 @@ export class Verify { }); const bound = boundString === '' ? 20 : parseInt(boundString!); check() - .then(() => runJar(["-j", tmpJson, "--smv", "-tmp"])) - .then(findSpecs) - .then(value => verifySpecsBmc(rcpPath, tmpJson, bound, value)) - .catch(vscode.window.showErrorMessage) + .then(() => runJar(["-j", tmpJson, "--smv", "-tmp"])) + .then(findSpecs) + .then(value => verifySpecsBmc(rcpPath, tmpJson, bound, value)) + .catch(vscode.window.showErrorMessage) }), vscode.commands.registerCommand('rcheck.tosmv', async () => { const rcpPath = getCurrentRcpFile()!; temp.toJson(rcpPath) - .then((tmpJson) => runJar(["-j", tmpJson, "--smv", "-tmp"])) - .then(value => { - const smvFile = value.stderr.trim(); - temp.addFile(smvFile); - return smvFile; - }) - .then(readPromise) - .then(showSmv) - .catch(vscode.window.showErrorMessage); + .then((tmpJson) => runJar(["-j", tmpJson, "--smv", "-tmp"])) + .then(value => { + const smvFile = value.stderr.trim(); + temp.addFile(smvFile); + return smvFile; + }) + .then(readPromise) + .then(showSmv) + .catch(vscode.window.showErrorMessage); }) ); ctx = context; @@ -73,13 +73,13 @@ async function showSmv(content: string) { "language": "nuxmv", "content": content }) - .then(doc => vscode.window.showTextDocument(doc)); + .then(doc => vscode.window.showTextDocument(doc)); } async function check() { return new Promise((resolve, reject) => { execFile("which", ["nuxmv"], (err, _) => { - if (err) {reject("This command requires nuxmv.")} + if (err) { reject("This command requires nuxmv.") } else resolve(); }); }); @@ -94,21 +94,26 @@ async function findSpecs(value: ExecResult) { return Promise.all([Promise.resolve(smvFile), execPromise("grep", ["-B", "1", "^LTLSPEC", smvFile])]); } +async function verifySpecsIc3(fname: string, json: string, v: [string, ExecResult]) { + verifySpecs(fname, json, ic3, v, "IC3"); +} + /** * Launch verification tasks */ -async function verifySpecsIc3(fname:string, json: string, v: [string, ExecResult]) { +async function verifySpecs(fname: string, json: string, fn: Function, v: [string, ExecResult], subtitle: string) { panel = vscode.window.createWebviewPanel( "verificationResults", "Verification Results", vscode.ViewColumn.Active, - {enableScripts: true, retainContextWhenHidden: true} + { enableScripts: true, retainContextWhenHidden: true } ); const tmpHtml = await renderTemplate( ctx, "verify.html", { - fname: fname, - body: undefined - }, + fname: fname, + subtitle: subtitle, + body: undefined + }, panel.webview); panel.webview.html = tmpHtml; @@ -120,7 +125,7 @@ async function verifySpecsIc3(fname:string, json: string, v: [string, ExecResult const body = await Promise .all(specs.map(async (element, index) => { const split = element.split("LTLSPEC").map((x) => x.trim()); - const nuxmvOutput = await ic3(v[0], index, split[1]); + const nuxmvOutput = await fn(v[0], index, split[1]); channel.appendLine(`[${fname}] ${++count}/${specs.length} done...`) return formatNuXmvOutput(split[0], json, nuxmvOutput); })) @@ -128,12 +133,13 @@ async function verifySpecsIc3(fname:string, json: string, v: [string, ExecResult channel.appendLine(`[${fname}] Done.`); return outputs.join(""); }); - panel.webview.html = await renderTemplate( - ctx, "verify.html", { - fname: fname, - body: body - }, - panel.webview); + panel.webview.html = await renderTemplate( + ctx, "verify.html", { + fname: fname, + subtitle: subtitle, + body: body + }, + panel.webview); } async function formatNuXmvOutput(spec: string, json: string, out: string) { @@ -155,7 +161,7 @@ async function formatNuXmvOutput(spec: string, json: string, out: string) { .then(v => JSON.parse(v.stdout), channel.appendLine) .then((cex: Step[]) => cex.map(async s => { const render = await renderTemplate( - ctx, "_step.html", + ctx, "_step.html", { deadlock: s.___DEADLOCK___, depth: s.depth, @@ -175,13 +181,13 @@ async function formatNuXmvOutput(spec: string, json: string, out: string) { .then(s => s.join("\n")); } const render = await renderTemplate( - ctx, "_verify.single.html", + ctx, "_verify.single.html", { - tbody: table, - spec: spec, - isTrue: isTrue, - isFalse: isFalse, - output: lines.join("\n") + tbody: table, + spec: spec, + isTrue: isTrue, + isFalse: isFalse, + output: lines.join("\n") }, panel.webview); return render; } @@ -192,7 +198,7 @@ async function formatNuXmvOutput(spec: string, json: string, out: string) { * @param index Index of property being verified * @param spec The LTLSPEC being verified */ -function ic3(fname: string, index: integer, spec: string, build_boolean_model: boolean=false) { +function ic3(fname: string, index: integer, spec: string, build_boolean_model: boolean = false) { // TODO If spec starts with G one can use check_property_as_invar_ic3 // TODO add optional ic3 bound limit in extension settings const smvCommands = ` @@ -205,7 +211,7 @@ function ic3(fname: string, index: integer, spec: string, build_boolean_model: b return new Promise((resolve, reject) => { writeFileSync(script, smvCommands); - const child = execFile("nuxmv", ["-source", script, fname], async (err,stdout,stderr) => { + const child = execFile("nuxmv", ["-source", script, fname], async (err, stdout, stderr) => { temp.rmChild(fname, child); temp.rm(script); if (err) { @@ -233,46 +239,6 @@ function ic3(fname: string, index: integer, spec: string, build_boolean_model: b }); } -/** - * Launch BMC verification tasks - */ -async function verifySpecsBmc(fname:string, json: string, bound: integer, v: [string, ExecResult]) { - const specs = v[1].stdout.trim().replace("\n", "").split("--").slice(1) - channel.show(); - channel.appendLine(`[${fname}] Model checking started...`); - const title = `R-CHECK: Verification of ${fname}` - let htmlReport = ` - - - - - ${title} - - -

${title}

` - - let count = 0; - const html = await Promise - .all(specs.map(async (element, index) => { - const split = element.split("LTLSPEC").map((x) => x.trim()); - const nuxmvOutput = await bmc(v[0], index, bound, split[1]); - channel.appendLine(`[${fname}] ${++count}/${specs.length} done...`); - return formatNuXmvOutput(split[0], json, nuxmvOutput); - })) - .then(outputs => { - channel.appendLine(`[${fname}] Done.`); - return `${htmlReport}${outputs.join("")}`; - }); - const panel = vscode.window.createWebviewPanel( - "verificationResults", - "Verification Results", - vscode.ViewColumn.Active, - {enableScripts: true, retainContextWhenHidden: true} - ); - panel.webview.html = html; -} - - /** * Verify an LTLSPEC property using BMC. * @param fname Name of the .smv file @@ -280,28 +246,36 @@ async function verifySpecsBmc(fname:string, json: string, bound: integer, v: [st * @param bound The BMC bound * @param spec The LTLSPEC being verified */ -function bmc(fname: string, index: integer, bound: integer, spec: string) { - const smvCommands = ` - set on_failure_script_quits 1 - go_msat - build_boolean_model - bmc_setup - msat_check_ltlspec_bmc -k ${bound} -p "${spec}" - quit`; - const script = temp.makeFile(`ltspec-${index}`, ".smv"); +async function verifySpecsBmc(fname: string, json: string, bound: integer, v: [string, ExecResult]) { + const bmcFn = makeBmcFn(bound); + verifySpecs(fname, json, bmcFn, v, `BMC (bound: ${bound})`); +} - return new Promise((resolve, reject) => { - writeFileSync(script, smvCommands); - const child = execFile("nuxmv", ["-source", script, fname], async (err,stdout,stderr) => { - temp.rmChild(fname, child); - temp.rm(script); - if (err) { - vscode.window.showErrorMessage(err.message); - reject(err.message); - } else { - resolve(stdout); - } + +function makeBmcFn(bound: integer) { + return function (fname: string, index: integer, spec: string) { + const smvCommands = ` + set on_failure_script_quits 1 + go_msat + build_boolean_model + bmc_setup + msat_check_ltlspec_bmc -k ${bound} -p "${spec}" + quit`; + const script = temp.makeFile(`ltspec-${index}`, ".smv"); + + return new Promise((resolve, reject) => { + writeFileSync(script, smvCommands); + const child = execFile("nuxmv", ["-source", script, fname], async (err, stdout, stderr) => { + temp.rmChild(fname, child); + temp.rm(script); + if (err) { + vscode.window.showErrorMessage(err.message); + reject(err.message); + } else { + resolve(stdout); + } + }); + temp.addChild(fname, child); }); - temp.addChild(fname, child); - }); -} \ No newline at end of file + } +}