From f6269033e4465674f2639f523b9521a4b662d89a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Loi=CC=88c=20Correnson?= <loic.correnson@cea.fr> Date: Mon, 11 Sep 2023 12:41:28 +0200 Subject: [PATCH] [wp] revisiting goal table --- ivette/src/frama-c/plugins/wp/api/index.ts | 61 ++++++++++++---- ivette/src/frama-c/plugins/wp/goals.tsx | 34 ++++----- src/plugins/wp/wpApi.ml | 81 ++++++++++++++-------- 3 files changed, 112 insertions(+), 64 deletions(-) diff --git a/ivette/src/frama-c/plugins/wp/api/index.ts b/ivette/src/frama-c/plugins/wp/api/index.ts index b4f1f05f214..d3ea8c14e71 100644 --- a/ivette/src/frama-c/plugins/wp/api/index.ts +++ b/ivette/src/frama-c/plugins/wp/api/index.ts @@ -112,6 +112,34 @@ export const resultDefault: result = { descr: '', cached: false, verdict: '', solverTime: 0, proverTime: 0, proverSteps: 0 }; +/** Test Status */ +export type status = + Json.key<'#NORESULT'> | Json.key<'#COMPUTING'> | Json.key<'#FAILED'> | + Json.key<'#STEPOUT'> | Json.key<'#UNKNOWN'> | Json.key<'#PASSED'> | + Json.key<'#VALID'> | Json.key<'#INVALID'>; + +/** Decoder for `status` */ +export const jStatus: Json.Decoder<status> = + Json.jUnion<Json.key<'#NORESULT'> | Json.key<'#COMPUTING'> | + Json.key<'#FAILED'> | Json.key<'#STEPOUT'> | + Json.key<'#UNKNOWN'> | Json.key<'#PASSED'> | + Json.key<'#VALID'> | Json.key<'#INVALID'>>( + Json.jKey<'#NORESULT'>('#NORESULT'), + Json.jKey<'#COMPUTING'>('#COMPUTING'), + Json.jKey<'#FAILED'>('#FAILED'), + Json.jKey<'#STEPOUT'>('#STEPOUT'), + Json.jKey<'#UNKNOWN'>('#UNKNOWN'), + Json.jKey<'#PASSED'>('#PASSED'), + Json.jKey<'#VALID'>('#VALID'), + Json.jKey<'#INVALID'>('#INVALID'), + ); + +/** Natural order for `status` */ +export const byStatus: Compare.Order<status> = Compare.structural; + +/** Default value for `status` */ +export const statusDefault: status = Json.jKey<'#NORESULT'>('#NORESULT')(''); + /** Prover Result */ export type stats = { summary: string, tactics: number, proved: number, total: number }; @@ -155,17 +183,19 @@ export interface goalsData { wpo: goal; /** Property Marker */ property: marker; - /** Informal name */ - name: string; /** Associated function, if any */ fct?: fct; /** Associated behavior, if any */ bhv?: string; /** Associated axiomatic, if any */ thy?: string; - /** Smoking (or not) goal and result */ - result: [ boolean, boolean ]; - /** Verdict Details */ + /** Informal Property Name */ + name: string; + /** Smoking (or not) goal */ + smoke: boolean; + /** Verdict, Status */ + status: status; + /** Prover Stats Summary */ stats: stats; /** Script File */ script?: string; @@ -178,11 +208,12 @@ export const jGoalsData: Json.Decoder<goalsData> = Json.jObject({ wpo: jGoal, property: jMarker, - name: Json.jString, fct: Json.jOption(jFct), bhv: Json.jOption(Json.jString), thy: Json.jOption(Json.jString), - result: Json.jPair( Json.jBoolean, Json.jBoolean,), + name: Json.jString, + smoke: Json.jBoolean, + status: jStatus, stats: jStats, script: Json.jOption(Json.jString), saved: Json.jBoolean, @@ -191,16 +222,17 @@ export const jGoalsData: Json.Decoder<goalsData> = /** Natural order for `goalsData` */ export const byGoalsData: Compare.Order<goalsData> = Compare.byFields - <{ wpo: goal, property: marker, name: string, fct?: fct, bhv?: string, - thy?: string, result: [ boolean, boolean ], stats: stats, + <{ wpo: goal, property: marker, fct?: fct, bhv?: string, thy?: string, + name: string, smoke: boolean, status: status, stats: stats, script?: string, saved: boolean }>({ wpo: byGoal, property: byMarker, - name: Compare.string, fct: Compare.defined(byFct), bhv: Compare.defined(Compare.string), thy: Compare.defined(Compare.string), - result: Compare.pair(Compare.boolean,Compare.boolean,), + name: Compare.string, + smoke: Compare.boolean, + status: byStatus, stats: byStats, script: Compare.defined(Compare.string), saved: Compare.boolean, @@ -255,9 +287,10 @@ export const goals: State.Array<goal,goalsData> = goals_internal; /** Default value for `goalsData` */ export const goalsDataDefault: goalsData = - { wpo: goalDefault, property: markerDefault, name: '', fct: undefined, - bhv: undefined, thy: undefined, result: [ false, false ], - stats: statsDefault, script: undefined, saved: false }; + { wpo: goalDefault, property: markerDefault, fct: undefined, + bhv: undefined, thy: undefined, name: '', smoke: false, + status: statusDefault, stats: statsDefault, script: undefined, + saved: false }; /** Proof Server Activity */ export const serverActivity: Server.Signal = { diff --git a/ivette/src/frama-c/plugins/wp/goals.tsx b/ivette/src/frama-c/plugins/wp/goals.tsx index 012d2a881ca..0e29a2d0ec9 100644 --- a/ivette/src/frama-c/plugins/wp/goals.tsx +++ b/ivette/src/frama-c/plugins/wp/goals.tsx @@ -21,30 +21,20 @@ /* ************************************************************************ */ import React from 'react'; -import { Icon } from 'dome/controls/icons'; -import { Table, Column, Renderer } from 'dome/table/views'; +import { Table, Column } from 'dome/table/views'; import * as Ivette from 'ivette'; import * as States from 'frama-c/states'; import * as WP from 'frama-c/plugins/wp/api'; -const renderResult: Renderer<[boolean, boolean]> = - ([smoking, passed]): JSX.Element => - (<Icon - id= - {passed ? 'CIRC.CHECK' : - (smoking ? 'CIRC.CLOSE' : 'CIRC.QUESTION') - } - fill= - {passed ? `var(--positive-button-color)` : - (smoking ? `var(--negative-button-color)` : `var(--warning-button-color)`) - } - />); +/* -------------------------------------------------------------------------- */ +/* --- Goals Table --- */ +/* -------------------------------------------------------------------------- */ function WPGoals(): JSX.Element { const model = States.useSyncArrayModel(WP.goals); // TODO: from AST selection, find WPO - const [_astSelection, updateAstSelection] = States.useSelection(); + const [_, updateAstSelection] = States.useSelection(); const [wpoSelection, setWpoSelection] = React.useState(WP.goalDefault); const onWpoSelection = React.useCallback( @@ -62,17 +52,15 @@ function WPGoals(): JSX.Element { onSelection={onWpoSelection} selection={wpoSelection} > - <Column id='fct' label='Function' /> - <Column id='name' label='Names' /> - <Column - id='result' - label='Result' - render={renderResult} - /> + <Column id='status' label='Status' fixed={true} width={80} /> + <Column id='name' label='Property' /> </Table> ); } +/* -------------------------------------------------------------------------- */ +/* --- Goals Component --- */ +/* -------------------------------------------------------------------------- */ Ivette.registerComponent({ id: 'frama-c.plugins.wp.goals', @@ -82,3 +70,5 @@ Ivette.registerComponent({ title: 'WP Generated Verification Conditions', children: <WPGoals />, }); + +/* -------------------------------------------------------------------------- */ diff --git a/src/plugins/wp/wpApi.ml b/src/plugins/wp/wpApi.ml index 0eec40b4198..a894d73e80f 100644 --- a/src/plugins/wp/wpApi.ml +++ b/src/plugins/wp/wpApi.ml @@ -105,9 +105,37 @@ struct ] end +module STATUS = +struct + type t = { smoke : bool ; verdict : VCS.verdict } + let jtype = D.declare ~package ~name:"status" + ~descr:(Md.plain "Test Status") + (Junion [ + Jkey "NORESULT" ; + Jkey "COMPUTING" ; + Jkey "FAILED" ; + Jkey "STEPOUT" ; + Jkey "UNKNOWN" ; + Jkey "PASSED" ; + Jkey "VALID" ; + Jkey "INVALID" ; + ]) + let to_json { smoke ; verdict } = + `String begin + match verdict with + | VCS.Valid -> if smoke then "INVALID" else "VALID" + | VCS.Unknown -> if smoke then "PASSED" else "UNKNOWN" + | Failed -> "FAILED" + | NoResult -> "NORESULT" + | Computing _ -> "COMPUTING" + | Timeout -> "TIMEOUT" + | Stepout -> "STEPOUT" + end +end + module STATS = struct - type t = bool * Stats.stats + type t = Stats.stats let jtype = D.declare ~package ~name:"stats" ~descr:(Md.plain "Prover Result") (Jrecord [ @@ -116,17 +144,8 @@ struct "proved", Jnumber; "total", Jnumber; ]) - let to_json (smoke,cs) : Json.t = - let verdict = match cs.Stats.best with - | VCS.Valid -> if smoke then "Doomed" else "Valid" - | VCS.Unknown -> if smoke then "Passed" else "Unknown" - | Failed -> "Failure" - | NoResult -> "No Result" - | Computing _ -> "Computing" - | Timeout -> "Timeout" - | Stepout -> "Stepout" - in - let summary = Format.asprintf "%s%a" verdict + let to_json cs : Json.t = + let summary = Pretty_utils.to_string (Stats.pp_stats ~shell:false ~cache:Update) cs in `Assoc [ "summary", `String summary ; @@ -150,11 +169,6 @@ let () = R.register ~package ~kind:`GET ~name:"getAvailableProvers" let gmodel : Wpo.t S.model = S.model () -let () = S.column gmodel ~name:"property" - ~descr:(Md.plain "Property Marker") - ~data:(module AST.Marker) - ~get:(fun g -> Printer_tag.PIP (WpPropId.property_of_id g.Wpo.po_pid)) - let get_kf g = match g.Wpo.po_idx with | Function(kf,_) -> Some kf | Axiomatic _ -> None @@ -167,11 +181,16 @@ let get_thy g = match g.Wpo.po_idx with | Function _ -> None | Axiomatic ax -> ax -let get_stats g = Wpo.is_smoke_test g, ProofEngine.consolidated g +let get_status g = + STATUS.{ + smoke = Wpo.is_smoke_test g ; + verdict = (ProofEngine.consolidated g).best ; + } -let () = S.column gmodel ~name:"name" - ~descr:(Md.plain "Informal name") ~data:(module D.Jstring) - ~get:(fun g -> g.Wpo.po_name) +let () = S.column gmodel ~name:"property" + ~descr:(Md.plain "Property Marker") + ~data:(module AST.Marker) + ~get:(fun g -> Printer_tag.PIP (WpPropId.property_of_id g.Wpo.po_pid)) let () = S.column gmodel ~name:"fct" ~descr:(Md.plain "Associated function, if any") @@ -185,16 +204,22 @@ let () = S.option gmodel ~name:"thy" ~descr:(Md.plain "Associated axiomatic, if any") ~data:(module D.Jstring) ~get:get_thy -let get_result g = - Wpo.is_smoke_test g, Wpo.is_passed g +let () = S.column gmodel ~name:"name" + ~descr:(Md.plain "Informal Property Name") + ~data:(module D.Jstring) + ~get:(fun g -> g.Wpo.po_name) + +let () = S.column gmodel ~name:"smoke" + ~descr:(Md.plain "Smoking (or not) goal") + ~data:(module D.Jbool) ~get:Wpo.is_smoke_test -let () = S.column gmodel ~name:"result" - ~descr:(Md.plain "Smoking (or not) goal and result") - ~data:(module D.Jpair (D.Jbool)(D.Jbool)) ~get:get_result +let () = S.column gmodel ~name:"status" + ~descr:(Md.plain "Verdict, Status") + ~data:(module STATUS) ~get:get_status let () = S.column gmodel ~name:"stats" - ~descr:(Md.plain "Verdict Details") - ~data:(module STATS) ~get:get_stats + ~descr:(Md.plain "Prover Stats Summary") + ~data:(module STATS) ~get:ProofEngine.consolidated let () = S.option gmodel ~name:"script" ~descr:(Md.plain "Script File") -- GitLab