From 5628b0bc12a1a0f69a61df470a33334642a50f43 Mon Sep 17 00:00:00 2001 From: Valentin Perrelle <valentin.perrelle@cea.fr> Date: Thu, 6 Oct 2022 21:52:02 +0200 Subject: [PATCH] [Dome] Use only safe decoders and throw exceptions when the decoded json mismatches - stricter conversion of tuples (checks list size) - stricter conversion of integers (checks that there is no fractional part) - jCatch only catches JsonErrors - more detailed error messages to debug the server interface - jUnion works more often - fixed several mistyping --- ivette/src/dome/renderer/data/json.ts | 495 +++++++++++------- ivette/src/dome/renderer/data/settings.ts | 28 +- ivette/src/dome/renderer/dome.tsx | 2 +- ivette/src/dome/renderer/table/views.tsx | 4 +- ivette/src/frama-c/kernel/ASTview.tsx | 3 +- ivette/src/frama-c/kernel/api/ast/index.ts | 171 +++--- ivette/src/frama-c/kernel/api/data/index.ts | 31 +- .../src/frama-c/kernel/api/project/index.ts | 29 +- .../frama-c/kernel/api/properties/index.ts | 72 +-- .../src/frama-c/kernel/api/services/index.ts | 77 ++- ivette/src/frama-c/plugins/dive/api/index.ts | 153 ++---- .../frama-c/plugins/eva/api/general/index.ts | 222 +++----- .../frama-c/plugins/eva/api/values/index.ts | 91 ++-- .../plugins/pivot/api/general/index.ts | 10 +- .../plugins/studia/api/studia/index.ts | 24 +- ivette/src/frama-c/server.ts | 4 +- ivette/src/renderer/Laboratory.tsx | 4 +- src/plugins/api-generator/api_generator.ml | 93 ++-- src/plugins/eva/api/general_requests.ml | 2 +- src/plugins/eva/api/values_request.ml | 2 +- src/plugins/server/data.ml | 21 +- src/plugins/server/data.mli | 1 - src/plugins/server/package.ml | 19 +- src/plugins/server/package.mli | 8 +- src/plugins/server/server_doc.ml | 6 +- 25 files changed, 671 insertions(+), 901 deletions(-) diff --git a/ivette/src/dome/renderer/data/json.ts b/ivette/src/dome/renderer/data/json.ts index 1d0f78cc81d..60f59d780f7 100644 --- a/ivette/src/dome/renderer/data/json.ts +++ b/ivette/src/dome/renderer/data/json.ts @@ -42,6 +42,20 @@ export type json = export type jobject = { [key: string]: json }; + +/* Parsing exceptions. + Stores a string telling what was expected and a json of what have been + given */ + +class JsonError extends Error { + expected = ''; + constructor(expected : string, given : json) { + super(`expected ${expected} but given ${given}`); + this.name = this.constructor.name; + this.expected = expected; + } +} + /** Parse without _revivals_. Returned data is guaranteed to have only [[json]] type. @@ -53,9 +67,15 @@ export function parse(text: string, noError = false): json { if (noError) { try { return JSON.parse(text); - } catch (err) { - D.error('Invalid format:', err); - return undefined; + } + catch (err) { + if (err instanceof JsonError) { + D.error(err); + return undefined; + } + else { + throw err; + } } } else return JSON.parse(text); @@ -76,21 +96,15 @@ export function pretty(js: any): string { } // -------------------------------------------------------------------------- -// --- SAFE Decoder +// --- Decoder & Encoder types // -------------------------------------------------------------------------- /** Decoder for values of type `D`. You can abbreviate `Safe<D | undefined>` with `Loose<D>`. */ -export interface Safe<D> { +export interface Decoder<D> { (js?: json): D; } -/** Decoder for values of type `D`, if any. - Same as `Safe<D | undefined>`. */ -export interface Loose<D> { - (js?: json): D | undefined; -} - /** Encoder for value of type `D`. In most cases, you only need [[identity]]. @@ -106,162 +120,181 @@ export function identity<A>(v: A): A { return v; } // --- Primitives // -------------------------------------------------------------------------- -/** 'null' or 'undefined'. */ -export const jNull: Loose<null> = (js: json) => - js === null ? null : undefined; +/** 'null' or throws JsonError. */ +export const jNull: Decoder<null> = (js: json) => { + if (js === null) { + return null; + } + else { + throw new JsonError("null", js); + } +}; /** Identity. */ -export const jAny: Safe<json> = (js: json) => js; +export const jAny: Decoder<json> = (js: json) => js; -/** JSON Object. */ -export const jObj: Loose<jobject> = (js: json) => ( - typeof js === 'object' && !Array.isArray(js) && js !== null ? js : undefined -); +/** JSON Object or throws JsonError. */ +export const jObj: Decoder<jobject> = (js: json) => { + if (typeof js === 'object' && !Array.isArray(js) && js !== null) { + return js; + } + else { + throw new JsonError("object", js); + } +}; -/** Primitive JSON number or `undefined`. */ -export const jNumber: Loose<number> = (js: json) => ( - typeof js === 'number' && !Number.isNaN(js) ? js : undefined -); +/** Primitive JSON number or throws JsonError. */ +export const jNumber: Decoder<number> = (js: json) => { + if (typeof js === 'number' && !Number.isNaN(js)) { + return js; + } + else { + throw new JsonError("object", js); + } +}; -/** Primitive JSON number, rounded to integer, or `undefined`. */ -export const jInt: Loose<number> = (js: json) => ( - typeof js === 'number' && !Number.isNaN(js) ? Math.round(js) : undefined -); +/** Primitive JSON number if it is an integer or throws JsonError. */ +export const jInt: Decoder<number> = (js: json) => { + if (typeof js === 'number' && Number.isInteger(js)) { + return js; + } + else { + throw new JsonError("integer", js); + } +}; /** Primitive JSON number or `0`. */ -export const jZero: Safe<number> = (js: json) => ( +export const jZero: Decoder<number> = (js: json) => ( typeof js === 'number' && !Number.isNaN(js) ? js : 0 ); -/** Primitive JSON boolean or `undefined`. */ -export const jBoolean: Loose<boolean> = (js: json) => ( - typeof js === 'boolean' ? js : undefined -); +/** Primitive JSON boolean or throws JsonError. */ +export const jBoolean: Decoder<boolean> = (js: json) => { + if (typeof js === 'boolean') { + return js; + } + else { + throw new JsonError("boolean", js); + } +}; /** Primitive JSON boolean or `true`. */ -export const jTrue: Safe<boolean> = (js: json) => ( +export const jTrue: Decoder<boolean> = (js: json) => ( typeof js === 'boolean' ? js : true ); /** Primitive JSON boolean or `false`. */ -export const jFalse: Safe<boolean> = (js: json) => ( +export const jFalse: Decoder<boolean> = (js: json) => ( typeof js === 'boolean' ? js : false ); -/** Primitive JSON string or `undefined`. */ -export const jString: Loose<string> = (js: json) => ( - typeof js === 'string' ? js : undefined -); +/** Primitive JSON string or throws JsonError. */ +export const jString: Decoder<string> = (js: json) => { + if (typeof js === 'string') { + return js; + } + else { + throw new JsonError("string", js); + } + }; + /** JSON constant. - Capture the tag or returns `undefined`. + Capture the tag or throw JsonError. Can be used with [[jUnion]], although [[jEnum]] might be more efficient. */ -export function jTag<A>(tg: A): Loose<A> { - return (js: json) => (Object.is(js, tg) ? tg : undefined); +export function jTag<A>(tg: A): Decoder<A> { + return (js: json) => { + if (Object.is(js, tg)) { + return tg; + } + else { + throw new JsonError(`"${tg}"`, js); + } + }; } /** - Lookup tags in a dictionary. + Lookup tags in a dictionary, throw JsonError if the tag is not found. Can be used directly for enum types, eg. `jEnum(myEnumType)`. */ -export function jEnum<A>(d: { [tag: string]: A }): Loose<A> { - return (v: json) => (typeof v === 'string' ? d[v] : undefined); +export function jEnum<A>(d: { [tag: string]: A }): Decoder<A> { + return (js: json) => { + if (typeof js === 'string' && js in d) { + return d[js]; + } + else { + const tags = Object.keys(d).map((tg) => `"${tg}"`); + throw new JsonError(tags.join(' | '), js); + } + }; } /** - One of the enumerated _constants_ or `undefined`. + One of the enumerated _constants_ or throws JsonError. The typechecker will prevent you from listing values that are not in type `A`. However, it will not protected you from missings constants in `A`. */ -export function jTags<A>(...values: ((string | number) & A)[]): Loose<A> { - const m = new Map<string | number, A>(); - values.forEach((v) => m.set(v, v)); - return (v: json) => (typeof v === 'string' ? m.get(v) : undefined); -} - -/** - Refine a loose decoder with some default value. - The default value is returned when the provided JSON is `undefined` or - when the loose decoder returns `undefined`. - */ -export function jDefault<A>( - fn: Loose<A>, - defaultValue: A, -): Safe<A> { - return (js: json) => ( - js === undefined ? defaultValue : (fn(js) ?? defaultValue) - ); +export function jTags<A extends string | number>(...values: A[]): Decoder<A> { + const m = new Set<string | number>(); + values.forEach((v) => m.add(v)); + return (js: json) => { + if ((typeof js === 'string' || typeof js === 'number') && m.has(js)) { + return js as A; // m.has(js) implies js extends A + } + else { + const tags = values.map((tg) => typeof tg === 'string' ? `"${tg}"` : tg); + throw new JsonError(tags.join(' | '), js); + } + }; } /** - Force returning `undefined` or a default value for - `undefined` _or_ `null` JSON input. - Typically useful to leverage an existing `Safe<A>` decoder. + Force returning `undefined` or a default value for `undefined` _or_ `null` + JSON input. */ -export function jOption<A>(fn: Safe<A>, defaultValue?: A): Loose<A> { +export function jOption<A>(fn: Decoder<A>, defaultValue?: A) + : Decoder<A | undefined> { return (js: json) => ( js === undefined || js === null ? defaultValue : fn(js) ); } /** - Fail when the loose decoder returns `undefined`. - See also [[jCatch]] and [[jTry]]. + Provide a fallback value in case of a JsonError. */ -export function jFail<A>(fn: Loose<A>, error: string | Error): Safe<A> { - return (js: json) => { - const d = fn(js); - if (d !== undefined) return d; - throw (typeof (error) === 'string' ? new Error(error) : error); - }; -} - -/** - Provide a fallback value in case of undefined value or error. - See also [[jFail]] and [[jTry]]. - */ -export function jCatch<A>(fn: Loose<A>, fallBack: A): Safe<A> { +export function jCatch<A>(fn: Decoder<A>, fallBack: A): Decoder<A> { return (js: json) => { try { - return fn(js) ?? fallBack; - } catch (err) { - D.warn(err); - return fallBack; + return fn(js); } - }; -} - -/** - Provides an (optional) default value in case of error or undefined value. - See also [[jFail]] and [[jCatch]]. - */ -export function jTry<A>(fn: Loose<A>, defaultValue?: A): Loose<A> { - return (js: json) => { - try { - return fn(js) ?? defaultValue; - } catch (err) { - D.warn(err); - return defaultValue; + catch (err) { + if (err instanceof JsonError) { + return fallBack; + } + else { + throw err; + } } }; } /** - Converts maps to dictionaries. + Converts objects to Maps. */ -export function jMap<A>(fn: Loose<A>): Safe<Map<string, A>> { +export function jMap<A>(fn: Decoder<A>): Decoder<Map<string, A>> { return (js: json) => { - const m = new Map<string, A>(); if (js !== null && typeof js === 'object' && !Array.isArray(js)) { - const keys = Object.keys(js); - keys.forEach((k) => { - const v = fn(js[k]); - if (v !== undefined) m.set(k, v); - }); + const m = new Map<string, A>(); + for (const k of Object.keys(js)) { + m.set(k, fn(js[k])); + } + return m; + } + else { + throw new JsonError('object', js); } - return m; }; } @@ -282,28 +315,46 @@ export function eMap<A>(fn: Encoder<A>): Encoder<Map<string, undefined | A>> { } /** - Apply the decoder on each item of a JSON array, or return `[]` otherwise. - Can be also applied on a _loose_ decoder, but you will get - an array with possibly `undefined` elements. Use [[jList]] - to discard undefined elements, or use a true _safe_ decoder. + Apply the decoder on each item of a JSON array or throw JsonError if + the decoded json is not an array. */ -export function jArray<A>(fn: Safe<A>): Safe<A[]> { - return (js: json) => (Array.isArray(js) ? js.map(fn) : []); +export function jArray<A>(fn: Decoder<A>): Decoder<A[]> { + return (js: json) => { + if (Array.isArray(js)) { + return js.map(fn); + } + else { + throw new JsonError('array', js); + } + }; } /** - Apply the loose decoder on each item of a JSON array, discarding - all `undefined` elements. To keep the all possibly undefined array entries, - use [[jArray]] instead. - */ -export function jList<A>(fn: Loose<A>): Safe<A[]> { + Apply the decoder on each item of a JSON array, discarding + all errors. + */ +export function jList<A>(fn: Decoder<A>): Decoder<A[]> { return (js: json) => { - const buffer: A[] = []; - if (Array.isArray(js)) js.forEach((vj) => { - const d = fn(vj); - if (d !== undefined) buffer.push(d); - }); - return buffer; + if (Array.isArray(js)) { + const buffer = []; + for (const element of js) { + try { + buffer.push(fn(element)); + } + catch (err) { + if (err instanceof JsonError) { + continue; + } + else { + throw err; + } + } + } + return buffer; + } + else { + throw new JsonError('array', js); + } }; } @@ -323,105 +374,120 @@ export function eList<A>(fn: Encoder<A>): Encoder<(A | undefined)[]> { }; } -/** Apply a pair of decoders to JSON pairs, or return `undefined`. */ +/** Apply a pair of decoders to JSON pairs, or throw JsonError if not a pair. */ export function jPair<A, B>( - fa: Safe<A>, - fb: Safe<B>, -): Loose<[A, B]> { - return (js: json) => (Array.isArray(js) ? [ - fa(js[0]), - fb(js[1]), - ] : undefined); + fa: Decoder<A>, + fb: Decoder<B>, +): Decoder<[A, B]> { + return (js: json) => { + if (Array.isArray(js) && js.length === 2) { + return [fa(js[0]) as A, fb(js[1]) as B]; + } + else { + throw new JsonError('[A, B]', js); + } + }; } /** Similar to [[jPair]]. */ export function jTriple<A, B, C>( - fa: Safe<A>, - fb: Safe<B>, - fc: Safe<C>, -): Loose<[A, B, C]> { - return (js: json) => (Array.isArray(js) ? [ - fa(js[0]), - fb(js[1]), - fc(js[2]), - ] : undefined); + fa: Decoder<A>, + fb: Decoder<B>, + fc: Decoder<C>, +): Decoder<[A, B, C]> { + return (js: json) => { + if (Array.isArray(js) && js.length === 3) { + return [fa(js[0]), fb(js[1]), fc(js[2])]; + } + else { + throw new JsonError('[A, B, C]', js); + } + }; } /** Similar to [[jPair]]. */ export function jTuple4<A, B, C, D>( - fa: Safe<A>, - fb: Safe<B>, - fc: Safe<C>, - fd: Safe<D>, -): Loose<[A, B, C, D]> { - return (js: json) => (Array.isArray(js) ? [ - fa(js[0]), - fb(js[1]), - fc(js[2]), - fd(js[3]), - ] : undefined); + fa: Decoder<A>, + fb: Decoder<B>, + fc: Decoder<C>, + fd: Decoder<D>, +): Decoder<[A, B, C, D]> { + return (js: json) => { + if (Array.isArray(js) && js.length === 4) { + return [fa(js[0]), fb(js[1]), fc(js[2]), fd(js[3])]; + } + else { + throw new JsonError('[A, B, C, D]', js); + } + }; } /** Similar to [[jPair]]. */ export function jTuple5<A, B, C, D, E>( - fa: Safe<A>, - fb: Safe<B>, - fc: Safe<C>, - fd: Safe<D>, - fe: Safe<E>, -): Loose<[A, B, C, D, E]> { - return (js: json) => (Array.isArray(js) ? [ - fa(js[0]), - fb(js[1]), - fc(js[2]), - fd(js[3]), - fe(js[4]), - ] : undefined); + fa: Decoder<A>, + fb: Decoder<B>, + fc: Decoder<C>, + fd: Decoder<D>, + fe: Decoder<E>, +): Decoder<[A, B, C, D, E]> { + return (js: json) => { + if (Array.isArray(js) && js.length === 5) { + return [fa(js[0]), fb(js[1]), fc(js[2]), fd(js[3]), fe(js[4])]; + } + else { + throw new JsonError('[A, B, C, D, E]', js); + } + }; } /** Decoders for each property of object type `A`. - Optional fields in `A` can be assigned a loose decoder. + Optional fields in `A` can use jOption */ export type Props<A> = { - [P in keyof A]: Safe<A[P]>; + [P in (keyof A & string)] : Decoder<A[P]>; }; /** Decode an object given the decoders of its fields. Returns `undefined` for non-object JSON. */ -export function jObject<A>(fp: Props<A>): Loose<A> { +export function jObject<A extends object>(decoders: Props<A>): Decoder<A> { return (js: json) => { if (js !== null && typeof js === 'object' && !Array.isArray(js)) { - const buffer = {} as A; - const keys = Object.keys(fp); - keys.forEach((k) => { - const fn = fp[k as keyof A]; - if (fn !== undefined) { - const fj = js[k]; - if (fj !== undefined) { - const fv = fn(fj); - if (fv !== undefined) buffer[k as keyof A] = fv; - } - } - }); - return buffer; + const buffer : Partial<A> = {}; + for (const k of Object.keys(decoders) as (keyof A & string)[]) { + buffer[k] = decoders[k](js[k]); + } + return buffer as A; // All fields should be present + } + else { + throw new JsonError('object', js); } - return undefined; }; } /** - Returns the first decoder result that is not undefined. + Returns the first decoder result that does not fail with a JsonError. */ -export function jUnion<A>(...cases: Loose<A>[]): Loose<A> { +export function jUnion<A>(...cases: Decoder<A>[]): Decoder<A> { return (js: json) => { - for (let i = 0; i < cases.length; i++) { - const fv = cases[i](js); - if (fv !== undefined) return fv; + const errors = []; + for (const fv of cases) { + try { + return fv(js); + } + catch (err) { + if (err instanceof JsonError) { + errors.push(err.expected); + continue; + } + else { + throw err; + } + } } - return undefined; + throw new JsonError(errors.join(' or '), js); }; } @@ -463,7 +529,7 @@ declare const tag: unique symbol; export type phantom<K, A> = A & { tag: K }; export function forge<K, A>(_tag: K, data: A): phantom<K, A> { - return data as any; + return data as phantom<K, A>; } /** String key with kind. @@ -475,13 +541,27 @@ export type key<K> = phantom<K, string>; export type index<K> = phantom<K, number>; /** Decoder for `key<K>` strings. */ -export function jKey<K>(kd: K): Loose<key<K>> { - return (js: json) => (typeof js === 'string' ? forge(kd, js) : undefined); +export function jKey<K>(kd: K): Decoder<key<K>> { + return (js: json) => { + if (typeof js === 'string') { + return forge(kd, js); + } + else { + throw new JsonError(`key<${kd}>`, js); + } + }; } /** Decoder for `index<K>` numbers. */ -export function jIndex<K>(kd: K): Loose<index<K>> { - return (js: json) => (typeof js === 'number' ? forge(kd, js) : undefined); +export function jIndex<K>(kd: K): Decoder<index<K>> { + return (js: json) => { + if (typeof js === 'number') { + return forge(kd, js); + } + else { + throw new JsonError(`index<${kd}>`, js); + } + }; } /** Dictionaries. */ @@ -491,23 +571,32 @@ export type dict<A> = { [key: string]: A }; Decode a JSON dictionary, discarding all inconsistent entries. If the JSON contains no valid entry, still returns `{}`. */ -export function jDict<A>(fn: Loose<A>): Safe<dict<A>> { +export function jDict<A>(fn: Decoder<A>): Decoder<dict<A>> { return (js: json) => { const buffer: dict<A> = {}; if (js !== null && typeof js === 'object' && !Array.isArray(js)) { - const keys = Object.keys(js); - keys.forEach((key) => { - const fd = js[key]; - if (fd !== undefined) { - const fv = fn(fd); - if (fv !== undefined) buffer[key] = fv; + for (const k of Object.keys(js)) { + try { + const fv = fn(js[k]); + if (fv !== undefined) { + buffer[k] = fv; + } + } + catch (err) { + if (err instanceof JsonError) { + continue; + } + else { + throw err; + } } - }); + } } return buffer; }; } + /** Encode a dictionary into JSON, discarding all inconsistent entries. If the dictionary contains no valid entry, still returns `{}`. diff --git a/ivette/src/dome/renderer/data/settings.ts b/ivette/src/dome/renderer/data/settings.ts index 7678c516a52..1da27fc8c05 100644 --- a/ivette/src/dome/renderer/data/settings.ts +++ b/ivette/src/dome/renderer/data/settings.ts @@ -44,7 +44,7 @@ import type { State } from './states'; /** @internal */ interface Settings<A> { - decoder: JSON.Loose<A>; + decoder: JSON.Decoder<A>; encoder: JSON.Encoder<A>; defaultValue: A; } @@ -62,12 +62,12 @@ interface Settings<A> { */ export class GlobalSettings<A> { name: string; - decoder: JSON.Loose<A>; + decoder: JSON.Decoder<A>; encoder: JSON.Encoder<A>; defaultValue: A; constructor( name: string, - decoder: JSON.Loose<A>, + decoder: JSON.Decoder<A>, encoder: JSON.Encoder<A>, defaultValue: A, ) { @@ -114,22 +114,22 @@ export class GString extends GlobalSettings<string> { export class GOption<A extends JSON.json> extends GlobalSettings<A | undefined> { - constructor(name: string, encoder: JSON.Loose<A>, defaultValue?: A) { + constructor(name: string, encoder: JSON.Decoder<A>, defaultValue?: A) { super(name, encoder, JSON.identity, defaultValue); } } /** Smart constructor for (JSON serializable) data with default. */ export class GDefault<A extends JSON.json> extends GlobalSettings<A> { - constructor(name: string, encoder: JSON.Loose<A>, defaultValue: A) { + constructor(name: string, encoder: JSON.Decoder<A>, defaultValue: A) { super(name, encoder, JSON.identity, defaultValue); } } /** Smart constructor for object (JSON serializable) data. */ -export class GObject<A extends JSON.json> extends GlobalSettings<A> { +export class GObject<A extends JSON.json & object> extends GlobalSettings<A> { constructor(name: string, fields: JSON.Props<A>, defaultValue: A) { - super(name, JSON.jObject(fields), JSON.identity, defaultValue); + super(name, JSON.jObject<A>(fields), JSON.identity, defaultValue); } } @@ -248,7 +248,7 @@ function useSettings<A>( ): State<A> { // Local State const [value, setValue] = React.useState<A>(() => ( - JSON.jCatch(S.decoder, S.defaultValue)(D.load(K)) + JSON.jCatch(S.decoder, S.defaultValue)(D.load(K)) ?? S.defaultValue )); // Foreign Settings Update React.useEffect(() => { @@ -288,7 +288,7 @@ const WindowSettingsDriver = new Driver({ */ export function getWindowSettings<A>( key: string | undefined, - decoder: JSON.Loose<A>, + decoder: JSON.Decoder<A>, defaultValue: A, ): A { return key ? @@ -316,7 +316,7 @@ export function setWindowSettings( */ export function useWindowSettings<A>( key: string | undefined, - decoder: JSON.Loose<A & JSON.json>, + decoder: JSON.Decoder<A & JSON.json>, defaultValue: A & JSON.json, ): State<A & JSON.json> { return useSettings({ @@ -329,7 +329,7 @@ export function useWindowSettings<A>( /** Same as [[useWindowSettings]] with a specific encoder. */ export function useWindowSettingsData<A>( key: string | undefined, - decoder: JSON.Loose<A>, + decoder: JSON.Decoder<A>, encoder: JSON.Encoder<A>, defaultValue: A, ): State<A> { @@ -377,7 +377,7 @@ const LocalStorageDriver = new Driver({ */ export function getLocalStorage<A>( key: string | undefined, - decoder: JSON.Loose<A>, + decoder: JSON.Decoder<A>, defaultValue: A, ): A { return key ? @@ -400,7 +400,7 @@ export function setLocalStorage( export function useLocalStorage<A>( key: string | undefined, - decoder: JSON.Loose<A & JSON.json>, + decoder: JSON.Decoder<A & JSON.json>, defaultValue: A & JSON.json, ): State<A & JSON.json> { return useSettings<A & JSON.json>({ @@ -413,7 +413,7 @@ export function useLocalStorage<A>( /** Same as [[useLocalStorage]] with a specific encoder. */ export function useLocalStorageData<A>( key: string | undefined, - decoder: JSON.Loose<A>, + decoder: JSON.Decoder<A>, encoder: JSON.Encoder<A>, defaultValue: A, ): State<A> { diff --git a/ivette/src/dome/renderer/dome.tsx b/ivette/src/dome/renderer/dome.tsx index 98369b95976..ef88eecd134 100644 --- a/ivette/src/dome/renderer/dome.tsx +++ b/ivette/src/dome/renderer/dome.tsx @@ -804,7 +804,7 @@ export const { useWindowSettings } = Settings; */ export function useGlobalSettings<A extends Json.json>( globalKey: string, - decoder: Json.Loose<A>, + decoder: Json.Decoder<A>, defaultValue: A, ): State<A> { // Object creation is cheaper than useMemo... diff --git a/ivette/src/dome/renderer/table/views.tsx b/ivette/src/dome/renderer/table/views.tsx index 9277450ebf6..a4bfc26d338 100644 --- a/ivette/src/dome/renderer/table/views.tsx +++ b/ivette/src/dome/renderer/table/views.tsx @@ -298,7 +298,7 @@ type TableSettings = { visible?: Json.dict<boolean>; }; -const jTableSettings = Json.jObject({ +const jTableSettings = Json.jObject<TableSettings>({ resize: Json.jDict(Json.jNumber), visible: Json.jDict(Json.jBoolean), }); @@ -450,7 +450,7 @@ class TableState<Key, Row> { const { visible } = this; resize.clear(); visible.clear(); - const theSettings: undefined | TableSettings = + const theSettings = Settings.getWindowSettings(settings, jTableSettings, undefined); if (theSettings) { forEach(theSettings.resize, (cw, cid) => { diff --git a/ivette/src/frama-c/kernel/ASTview.tsx b/ivette/src/frama-c/kernel/ASTview.tsx index 6b1dd2729ad..17cad6c4aff 100644 --- a/ivette/src/frama-c/kernel/ASTview.tsx +++ b/ivette/src/frama-c/kernel/ASTview.tsx @@ -29,6 +29,7 @@ import _ from 'lodash'; import CodeMirror from 'codemirror/lib/codemirror'; import * as Dome from 'dome'; +import * as Json from 'dome/data/json'; import * as Settings from 'dome/data/settings'; import { TitleBar } from 'ivette'; import { IconButton } from 'dome/controls/buttons'; @@ -241,7 +242,7 @@ export default function ASTview(): JSX.Element { }, [buffer, theMarker]); function onHover(markerId?: string): void { - const marker = Ast.jMarker(markerId); + const marker = Json.jOption(Ast.jMarker)(markerId); const fct = selection?.current?.fct; States.setHovered(marker ? { fct, marker } : undefined); } diff --git a/ivette/src/frama-c/kernel/api/ast/index.ts b/ivette/src/frama-c/kernel/api/ast/index.ts index fe8ebaddbc4..c44b83fac40 100644 --- a/ivette/src/frama-c/kernel/api/ast/index.ts +++ b/ivette/src/frama-c/kernel/api/ast/index.ts @@ -44,12 +44,8 @@ import { byText } from 'frama-c/kernel/api/data'; //@ts-ignore import { jTag } from 'frama-c/kernel/api/data'; //@ts-ignore -import { jTagSafe } from 'frama-c/kernel/api/data'; -//@ts-ignore import { jText } from 'frama-c/kernel/api/data'; //@ts-ignore -import { jTextSafe } from 'frama-c/kernel/api/data'; -//@ts-ignore import { tag } from 'frama-c/kernel/api/data'; //@ts-ignore import { text } from 'frama-c/kernel/api/data'; @@ -73,19 +69,15 @@ export const changed: Server.Signal = { export type source = { dir: string, base: string, file: string, line: number }; -/** Loose decoder for `source` */ -export const jSource: Json.Loose<source> = +/** Decoder for `source` */ +export const jSource: Json.Decoder<source> = Json.jObject({ - dir: Json.jFail(Json.jString,'String expected'), - base: Json.jFail(Json.jString,'String expected'), - file: Json.jFail(Json.jString,'String expected'), - line: Json.jFail(Json.jNumber,'Number expected'), + dir: Json.jString, + base: Json.jString, + file: Json.jString, + line: Json.jNumber, }); -/** Safe decoder for `source` */ -export const jSourceSafe: Json.Safe<source> = - Json.jFail(jSource,'Source expected'); - /** Natural order for `source` */ export const bySource: Compare.Order<source> = Compare.byFields @@ -114,12 +106,8 @@ export enum markerKind { property = 'property', } -/** Loose decoder for `markerKind` */ -export const jMarkerKind: Json.Loose<markerKind> = Json.jEnum(markerKind); - -/** Safe decoder for `markerKind` */ -export const jMarkerKindSafe: Json.Safe<markerKind> = - Json.jFail(Json.jEnum(markerKind),'kernel.ast.markerKind expected'); +/** Decoder for `markerKind` */ +export const jMarkerKind: Json.Decoder<markerKind> = Json.jEnum(markerKind); /** Natural order for `markerKind` */ export const byMarkerKind: Compare.Order<markerKind> = @@ -129,7 +117,7 @@ const markerKindTags_internal: Server.GetRequest<null,tag[]> = { kind: Server.RqKind.GET, name: 'kernel.ast.markerKindTags', input: Json.jNull, - output: Json.jList(jTag), + output: Json.jArray(jTag), signals: [], }; /** Registered tags for the above type. */ @@ -145,12 +133,8 @@ export enum markerVar { function = 'function', } -/** Loose decoder for `markerVar` */ -export const jMarkerVar: Json.Loose<markerVar> = Json.jEnum(markerVar); - -/** Safe decoder for `markerVar` */ -export const jMarkerVarSafe: Json.Safe<markerVar> = - Json.jFail(Json.jEnum(markerVar),'kernel.ast.markerVar expected'); +/** Decoder for `markerVar` */ +export const jMarkerVar: Json.Decoder<markerVar> = Json.jEnum(markerVar); /** Natural order for `markerVar` */ export const byMarkerVar: Compare.Order<markerVar> = @@ -160,7 +144,7 @@ const markerVarTags_internal: Server.GetRequest<null,tag[]> = { kind: Server.RqKind.GET, name: 'kernel.ast.markerVarTags', input: Json.jNull, - output: Json.jList(jTag), + output: Json.jArray(jTag), signals: [], }; /** Registered tags for the above type. */ @@ -182,21 +166,17 @@ export interface markerInfoData { sloc: source; } -/** Loose decoder for `markerInfoData` */ -export const jMarkerInfoData: Json.Loose<markerInfoData> = +/** Decoder for `markerInfoData` */ +export const jMarkerInfoData: Json.Decoder<markerInfoData> = Json.jObject({ - key: Json.jFail(Json.jString,'String expected'), - kind: jMarkerKindSafe, - var: jMarkerVarSafe, - name: Json.jFail(Json.jString,'String expected'), - descr: Json.jFail(Json.jString,'String expected'), - sloc: jSourceSafe, + key: Json.jString, + kind: jMarkerKind, + var: jMarkerVar, + name: Json.jString, + descr: Json.jString, + sloc: jSource, }); -/** Safe decoder for `markerInfoData` */ -export const jMarkerInfoDataSafe: Json.Safe<markerInfoData> = - Json.jFail(jMarkerInfoData,'MarkerInfoData expected'); - /** Natural order for `markerInfoData` */ export const byMarkerInfoData: Compare.Order<markerInfoData> = Compare.byFields @@ -234,10 +214,10 @@ const fetchMarkerInfo_internal: Server.GetRequest< name: 'kernel.ast.fetchMarkerInfo', input: Json.jNumber, output: Json.jObject({ - pending: Json.jFail(Json.jNumber,'Number expected'), - updated: Json.jList(jMarkerInfoData), - removed: Json.jList(Json.jString), - reload: Json.jFail(Json.jBoolean,'Boolean expected'), + pending: Json.jNumber, + updated: Json.jArray(jMarkerInfoData), + removed: Json.jArray(Json.jString), + reload: Json.jBoolean, }), signals: [], }; @@ -265,8 +245,8 @@ export type marker = Json.key<'#expr'> | Json.key<'#term'> | Json.key<'#global'> | Json.key<'#property'>; -/** Loose decoder for `marker` */ -export const jMarker: Json.Loose<marker> = +/** Decoder for `marker` */ +export const jMarker: Json.Decoder<marker> = Json.jUnion<Json.key<'#stmt'> | Json.key<'#decl'> | Json.key<'#lval'> | Json.key<'#expr'> | Json.key<'#term'> | Json.key<'#global'> | Json.key<'#property'>>( @@ -279,10 +259,6 @@ export const jMarker: Json.Loose<marker> = Json.jKey<'#property'>('#property'), ); -/** Safe decoder for `marker` */ -export const jMarkerSafe: Json.Safe<marker> = - Json.jFail(jMarker,'Marker expected'); - /** Natural order for `marker` */ export const byMarker: Compare.Order<marker> = Compare.structural; @@ -294,16 +270,9 @@ export interface location { marker: marker; } -/** Loose decoder for `location` */ -export const jLocation: Json.Loose<location> = - Json.jObject({ - fct: Json.jFail(Json.jKey<'#fct'>('#fct'),'#fct expected'), - marker: jMarkerSafe, - }); - -/** Safe decoder for `location` */ -export const jLocationSafe: Json.Safe<location> = - Json.jFail(jLocation,'Location expected'); +/** Decoder for `location` */ +export const jLocation: Json.Decoder<location> = + Json.jObject({ fct: Json.jKey<'#fct'>('#fct'), marker: jMarker,}); /** Natural order for `location` */ export const byLocation: Compare.Order<location> = @@ -321,7 +290,7 @@ const getMainFunction_internal: Server.GetRequest< kind: Server.RqKind.GET, name: 'kernel.ast.getMainFunction', input: Json.jNull, - output: Json.jKey<'#fct'>('#fct'), + output: Json.jOption(Json.jKey<'#fct'>('#fct')), signals: [], }; /** Get the current 'main' function. */ @@ -335,7 +304,7 @@ const getFunctions_internal: Server.GetRequest<null,Json.key<'#fct'>[]> = { kind: Server.RqKind.GET, name: 'kernel.ast.getFunctions', input: Json.jNull, - output: Json.jList(Json.jKey<'#fct'>('#fct')), + output: Json.jArray(Json.jKey<'#fct'>('#fct')), signals: [], }; /** Collect all functions in the AST */ @@ -371,24 +340,19 @@ export interface functionsData { sloc: source; } -/** Loose decoder for `functionsData` */ -export const jFunctionsData: Json.Loose<functionsData> = +/** Decoder for `functionsData` */ +export const jFunctionsData: Json.Decoder<functionsData> = Json.jObject({ - key: Json.jFail(Json.jKey<'#functions'>('#functions'), - '#functions expected'), - name: Json.jFail(Json.jString,'String expected'), - signature: Json.jFail(Json.jString,'String expected'), - main: Json.jBoolean, - defined: Json.jBoolean, - stdlib: Json.jBoolean, - builtin: Json.jBoolean, - sloc: jSourceSafe, + key: Json.jKey<'#functions'>('#functions'), + name: Json.jString, + signature: Json.jString, + main: Json.jOption(Json.jBoolean), + defined: Json.jOption(Json.jBoolean), + stdlib: Json.jOption(Json.jBoolean), + builtin: Json.jOption(Json.jBoolean), + sloc: jSource, }); -/** Safe decoder for `functionsData` */ -export const jFunctionsDataSafe: Json.Safe<functionsData> = - Json.jFail(jFunctionsData,'FunctionsData expected'); - /** Natural order for `functionsData` */ export const byFunctionsData: Compare.Order<functionsData> = Compare.byFields @@ -429,10 +393,10 @@ const fetchFunctions_internal: Server.GetRequest< name: 'kernel.ast.fetchFunctions', input: Json.jNumber, output: Json.jObject({ - pending: Json.jFail(Json.jNumber,'Number expected'), - updated: Json.jList(jFunctionsData), - removed: Json.jList(Json.jKey<'#functions'>('#functions')), - reload: Json.jFail(Json.jBoolean,'Boolean expected'), + pending: Json.jNumber, + updated: Json.jArray(jFunctionsData), + removed: Json.jArray(Json.jKey<'#functions'>('#functions')), + reload: Json.jBoolean, }), signals: [], }; @@ -466,14 +430,14 @@ const getInformation_internal: Server.GetRequest< > = { kind: Server.RqKind.GET, name: 'kernel.ast.getInformation', - input: jMarker, - output: Json.jList( + input: Json.jOption(jMarker), + output: Json.jArray( Json.jObject({ - id: Json.jFail(Json.jString,'String expected'), - label: Json.jFail(Json.jString,'String expected'), - descr: Json.jFail(Json.jString,'String expected'), - title: Json.jFail(Json.jString,'String expected'), - text: jTextSafe, + id: Json.jString, + label: Json.jString, + descr: Json.jString, + title: Json.jString, + text: jText, })), signals: [ { name: 'kernel.ast.getInformationUpdate' } ], }; @@ -490,13 +454,11 @@ const getMarkerAt_internal: Server.GetRequest< > = { kind: Server.RqKind.GET, name: 'kernel.ast.getMarkerAt', - input: Json.jTry( - Json.jTriple( - Json.jFail(Json.jString,'String expected'), - Json.jFail(Json.jNumber,'Number expected'), - Json.jFail(Json.jNumber,'Number expected'), - )), - output: Json.jTry(Json.jPair( Json.jKey<'#fct'>('#fct'), jMarker,)), + input: Json.jTriple( Json.jString, Json.jNumber, Json.jNumber,), + output: Json.jPair( + Json.jOption(Json.jKey<'#fct'>('#fct')), + Json.jOption(jMarker), + ), signals: [], }; /** Returns the marker and function at a source file position, if any. Input: file path, line and column. */ @@ -509,7 +471,7 @@ const getFiles_internal: Server.GetRequest<null,string[]> = { kind: Server.RqKind.GET, name: 'kernel.ast.getFiles', input: Json.jNull, - output: Json.jList(Json.jString), + output: Json.jArray(Json.jString), signals: [], }; /** Get the currently analyzed source file names */ @@ -518,7 +480,7 @@ export const getFiles: Server.GetRequest<null,string[]>= getFiles_internal; const setFiles_internal: Server.SetRequest<string[],null> = { kind: Server.RqKind.SET, name: 'kernel.ast.setFiles', - input: Json.jList(Json.jString), + input: Json.jArray(Json.jString), output: Json.jNull, signals: [], }; @@ -533,16 +495,9 @@ export interface markerFromTermInput { term: string; } -/** Loose decoder for `markerFromTermInput` */ -export const jMarkerFromTermInput: Json.Loose<markerFromTermInput> = - Json.jObject({ - atStmt: jMarkerSafe, - term: Json.jFail(Json.jString,'String expected'), - }); - -/** Safe decoder for `markerFromTermInput` */ -export const jMarkerFromTermInputSafe: Json.Safe<markerFromTermInput> = - Json.jFail(jMarkerFromTermInput,'MarkerFromTermInput expected'); +/** Decoder for `markerFromTermInput` */ +export const jMarkerFromTermInput: Json.Decoder<markerFromTermInput> = + Json.jObject({ atStmt: jMarker, term: Json.jString,}); /** Natural order for `markerFromTermInput` */ export const byMarkerFromTermInput: Compare.Order<markerFromTermInput> = @@ -560,7 +515,7 @@ const markerFromTerm_internal: Server.GetRequest< kind: Server.RqKind.GET, name: 'kernel.ast.markerFromTerm', input: jMarkerFromTermInput, - output: jMarker, + output: Json.jOption(jMarker), signals: [], }; /** Build a marker from an ACSL term. */ diff --git a/ivette/src/frama-c/kernel/api/data/index.ts b/ivette/src/frama-c/kernel/api/data/index.ts index 0ffe39eb16c..b16fbfb9b84 100644 --- a/ivette/src/frama-c/kernel/api/data/index.ts +++ b/ivette/src/frama-c/kernel/api/data/index.ts @@ -41,12 +41,8 @@ import * as State from 'frama-c/states'; /** Markdown (inlined) text. */ export type markdown = string; -/** Loose decoder for `markdown` */ -export const jMarkdown: Json.Loose<markdown> = Json.jString; - -/** Safe decoder for `markdown` */ -export const jMarkdownSafe: Json.Safe<markdown> = - Json.jFail(Json.jString,'String expected'); +/** Decoder for `markdown` */ +export const jMarkdown: Json.Decoder<markdown> = Json.jString; /** Natural order for `markdown` */ export const byMarkdown: Compare.Order<markdown> = Compare.string; @@ -54,18 +50,14 @@ export const byMarkdown: Compare.Order<markdown> = Compare.string; /** Rich text format uses `[tag; …text ]` to apply the tag `tag` to the enclosed text. Empty tag `""` can also used to simply group text together. */ export type text = null | string | text[]; -/** Loose decoder for `text` */ -export const jText: Json.Loose<text> = +/** Decoder for `text` */ +export const jText: Json.Decoder<text> = (_x: any) => Json.jUnion<null | string | text[]>( Json.jNull, Json.jString, - Json.jList(jText), + Json.jArray(jText), )(_x); -/** Safe decoder for `text` */ -export const jTextSafe: Json.Safe<text> = - (_x: any) => Json.jFail(jText,'Text expected')(_x); - /** Natural order for `text` */ export const byText: Compare.Order<text> = (_x: any, _y: any) => Compare.structural(_x,_y); @@ -73,16 +65,9 @@ export const byText: Compare.Order<text> = /** Enum Tag Description */ export type tag = { name: string, label: markdown, descr: markdown }; -/** Loose decoder for `tag` */ -export const jTag: Json.Loose<tag> = - Json.jObject({ - name: Json.jFail(Json.jString,'String expected'), - label: jMarkdownSafe, - descr: jMarkdownSafe, - }); - -/** Safe decoder for `tag` */ -export const jTagSafe: Json.Safe<tag> = Json.jFail(jTag,'Tag expected'); +/** Decoder for `tag` */ +export const jTag: Json.Decoder<tag> = + Json.jObject({ name: Json.jString, label: jMarkdown, descr: jMarkdown,}); /** Natural order for `tag` */ export const byTag: Compare.Order<tag> = diff --git a/ivette/src/frama-c/kernel/api/project/index.ts b/ivette/src/frama-c/kernel/api/project/index.ts index 1c99f90e498..9a103ff07d9 100644 --- a/ivette/src/frama-c/kernel/api/project/index.ts +++ b/ivette/src/frama-c/kernel/api/project/index.ts @@ -42,18 +42,14 @@ import * as State from 'frama-c/states'; export type projectInfo = { id: Json.key<'#project'>, name: string, current: boolean }; -/** Loose decoder for `projectInfo` */ -export const jProjectInfo: Json.Loose<projectInfo> = +/** Decoder for `projectInfo` */ +export const jProjectInfo: Json.Decoder<projectInfo> = Json.jObject({ - id: Json.jFail(Json.jKey<'#project'>('#project'),'#project expected'), - name: Json.jFail(Json.jString,'String expected'), - current: Json.jFail(Json.jBoolean,'Boolean expected'), + id: Json.jKey<'#project'>('#project'), + name: Json.jString, + current: Json.jBoolean, }); -/** Safe decoder for `projectInfo` */ -export const jProjectInfoSafe: Json.Safe<projectInfo> = - Json.jFail(jProjectInfo,'ProjectInfo expected'); - /** Natural order for `projectInfo` */ export const byProjectInfo: Compare.Order<projectInfo> = Compare.byFields @@ -67,19 +63,14 @@ export const byProjectInfo: Compare.Order<projectInfo> = export type projectRequest = { project: Json.key<'#project'>, request: string, data: Json.json }; -/** Loose decoder for `projectRequest` */ -export const jProjectRequest: Json.Loose<projectRequest> = +/** Decoder for `projectRequest` */ +export const jProjectRequest: Json.Decoder<projectRequest> = Json.jObject({ - project: Json.jFail(Json.jKey<'#project'>('#project'), - '#project expected'), - request: Json.jFail(Json.jString,'String expected'), + project: Json.jKey<'#project'>('#project'), + request: Json.jString, data: Json.jAny, }); -/** Safe decoder for `projectRequest` */ -export const jProjectRequestSafe: Json.Safe<projectRequest> = - Json.jFail(jProjectRequest,'ProjectRequest expected'); - /** Natural order for `projectRequest` */ export const byProjectRequest: Compare.Order<projectRequest> = Compare.byFields @@ -113,7 +104,7 @@ const getList_internal: Server.GetRequest<null,projectInfo[]> = { kind: Server.RqKind.GET, name: 'kernel.project.getList', input: Json.jNull, - output: Json.jList(jProjectInfo), + output: Json.jArray(jProjectInfo), signals: [], }; /** Returns the list of all projects */ diff --git a/ivette/src/frama-c/kernel/api/properties/index.ts b/ivette/src/frama-c/kernel/api/properties/index.ts index 86be4026c89..eab7ae40697 100644 --- a/ivette/src/frama-c/kernel/api/properties/index.ts +++ b/ivette/src/frama-c/kernel/api/properties/index.ts @@ -42,16 +42,12 @@ import { bySource } from 'frama-c/kernel/api/ast'; //@ts-ignore import { jSource } from 'frama-c/kernel/api/ast'; //@ts-ignore -import { jSourceSafe } from 'frama-c/kernel/api/ast'; -//@ts-ignore import { source } from 'frama-c/kernel/api/ast'; //@ts-ignore import { byTag } from 'frama-c/kernel/api/data'; //@ts-ignore import { jTag } from 'frama-c/kernel/api/data'; //@ts-ignore -import { jTagSafe } from 'frama-c/kernel/api/data'; -//@ts-ignore import { tag } from 'frama-c/kernel/api/data'; /** Property Kinds */ @@ -126,12 +122,8 @@ export enum propKind { extension = 'extension', } -/** Loose decoder for `propKind` */ -export const jPropKind: Json.Loose<propKind> = Json.jEnum(propKind); - -/** Safe decoder for `propKind` */ -export const jPropKindSafe: Json.Safe<propKind> = - Json.jFail(Json.jEnum(propKind),'kernel.properties.propKind expected'); +/** Decoder for `propKind` */ +export const jPropKind: Json.Decoder<propKind> = Json.jEnum(propKind); /** Natural order for `propKind` */ export const byPropKind: Compare.Order<propKind> = Compare.byEnum(propKind); @@ -140,7 +132,7 @@ const propKindTags_internal: Server.GetRequest<null,tag[]> = { kind: Server.RqKind.GET, name: 'kernel.properties.propKindTags', input: Json.jNull, - output: Json.jList(jTag), + output: Json.jArray(jTag), signals: [], }; /** Registered tags for the above type. */ @@ -172,12 +164,8 @@ export enum propStatus { unknown_but_dead = 'unknown_but_dead', } -/** Loose decoder for `propStatus` */ -export const jPropStatus: Json.Loose<propStatus> = Json.jEnum(propStatus); - -/** Safe decoder for `propStatus` */ -export const jPropStatusSafe: Json.Safe<propStatus> = - Json.jFail(Json.jEnum(propStatus),'kernel.properties.propStatus expected'); +/** Decoder for `propStatus` */ +export const jPropStatus: Json.Decoder<propStatus> = Json.jEnum(propStatus); /** Natural order for `propStatus` */ export const byPropStatus: Compare.Order<propStatus> = @@ -187,7 +175,7 @@ const propStatusTags_internal: Server.GetRequest<null,tag[]> = { kind: Server.RqKind.GET, name: 'kernel.properties.propStatusTags', input: Json.jNull, - output: Json.jList(jTag), + output: Json.jArray(jTag), signals: [], }; /** Registered tags for the above type. */ @@ -233,12 +221,8 @@ export enum alarms { bool_value = 'bool_value', } -/** Loose decoder for `alarms` */ -export const jAlarms: Json.Loose<alarms> = Json.jEnum(alarms); - -/** Safe decoder for `alarms` */ -export const jAlarmsSafe: Json.Safe<alarms> = - Json.jFail(Json.jEnum(alarms),'kernel.properties.alarms expected'); +/** Decoder for `alarms` */ +export const jAlarms: Json.Decoder<alarms> = Json.jEnum(alarms); /** Natural order for `alarms` */ export const byAlarms: Compare.Order<alarms> = Compare.byEnum(alarms); @@ -247,7 +231,7 @@ const alarmsTags_internal: Server.GetRequest<null,tag[]> = { kind: Server.RqKind.GET, name: 'kernel.properties.alarmsTags', input: Json.jNull, - output: Json.jList(jTag), + output: Json.jArray(jTag), signals: [], }; /** Registered tags for the above type. */ @@ -279,26 +263,22 @@ export interface statusData { predicate?: string; } -/** Loose decoder for `statusData` */ -export const jStatusData: Json.Loose<statusData> = +/** Decoder for `statusData` */ +export const jStatusData: Json.Decoder<statusData> = Json.jObject({ - key: Json.jFail(Json.jKey<'#property'>('#property'),'#property expected'), - descr: Json.jFail(Json.jString,'String expected'), - kind: jPropKindSafe, - names: Json.jList(Json.jString), - status: jPropStatusSafe, - fct: Json.jKey<'#fct'>('#fct'), - kinstr: Json.jKey<'#stmt'>('#stmt'), - source: jSourceSafe, - alarm: Json.jString, - alarm_descr: Json.jString, - predicate: Json.jString, + key: Json.jKey<'#property'>('#property'), + descr: Json.jString, + kind: jPropKind, + names: Json.jArray(Json.jString), + status: jPropStatus, + fct: Json.jOption(Json.jKey<'#fct'>('#fct')), + kinstr: Json.jOption(Json.jKey<'#stmt'>('#stmt')), + source: jSource, + alarm: Json.jOption(Json.jString), + alarm_descr: Json.jOption(Json.jString), + predicate: Json.jOption(Json.jString), }); -/** Safe decoder for `statusData` */ -export const jStatusDataSafe: Json.Safe<statusData> = - Json.jFail(jStatusData,'StatusData expected'); - /** Natural order for `statusData` */ export const byStatusData: Compare.Order<statusData> = Compare.byFields @@ -343,10 +323,10 @@ const fetchStatus_internal: Server.GetRequest< name: 'kernel.properties.fetchStatus', input: Json.jNumber, output: Json.jObject({ - pending: Json.jFail(Json.jNumber,'Number expected'), - updated: Json.jList(jStatusData), - removed: Json.jList(Json.jKey<'#property'>('#property')), - reload: Json.jFail(Json.jBoolean,'Boolean expected'), + pending: Json.jNumber, + updated: Json.jArray(jStatusData), + removed: Json.jArray(Json.jKey<'#property'>('#property')), + reload: Json.jBoolean, }), signals: [], }; diff --git a/ivette/src/frama-c/kernel/api/services/index.ts b/ivette/src/frama-c/kernel/api/services/index.ts index 56868eadf19..0319f3998c4 100644 --- a/ivette/src/frama-c/kernel/api/services/index.ts +++ b/ivette/src/frama-c/kernel/api/services/index.ts @@ -44,12 +44,8 @@ import { bySource } from 'frama-c/kernel/api/ast'; //@ts-ignore import { jMarker } from 'frama-c/kernel/api/ast'; //@ts-ignore -import { jMarkerSafe } from 'frama-c/kernel/api/ast'; -//@ts-ignore import { jSource } from 'frama-c/kernel/api/ast'; //@ts-ignore -import { jSourceSafe } from 'frama-c/kernel/api/ast'; -//@ts-ignore import { marker } from 'frama-c/kernel/api/ast'; //@ts-ignore import { source } from 'frama-c/kernel/api/ast'; @@ -58,8 +54,6 @@ import { byTag } from 'frama-c/kernel/api/data'; //@ts-ignore import { jTag } from 'frama-c/kernel/api/data'; //@ts-ignore -import { jTagSafe } from 'frama-c/kernel/api/data'; -//@ts-ignore import { tag } from 'frama-c/kernel/api/data'; const getConfig_internal: Server.GetRequest< @@ -70,9 +64,9 @@ const getConfig_internal: Server.GetRequest< name: 'kernel.services.getConfig', input: Json.jNull, output: Json.jObject({ - pluginpath: Json.jList(Json.jString), - datadir: Json.jList(Json.jString), - version: Json.jFail(Json.jString,'String expected'), + pluginpath: Json.jArray(Json.jString), + datadir: Json.jArray(Json.jString), + version: Json.jString, }), signals: [], }; @@ -86,7 +80,7 @@ const load_internal: Server.SetRequest<string,string | undefined> = { kind: Server.RqKind.SET, name: 'kernel.services.load', input: Json.jString, - output: Json.jString, + output: Json.jOption(Json.jString), signals: [], }; /** Load a save file. Returns an error, if not successfull. */ @@ -96,7 +90,7 @@ const save_internal: Server.SetRequest<string,string | undefined> = { kind: Server.RqKind.SET, name: 'kernel.services.save', input: Json.jString, - output: Json.jString, + output: Json.jOption(Json.jString), signals: [], }; /** Save the current session. Returns an error, if not successfull. */ @@ -118,12 +112,8 @@ export enum logkind { DEBUG = 'DEBUG', } -/** Loose decoder for `logkind` */ -export const jLogkind: Json.Loose<logkind> = Json.jEnum(logkind); - -/** Safe decoder for `logkind` */ -export const jLogkindSafe: Json.Safe<logkind> = - Json.jFail(Json.jEnum(logkind),'kernel.services.logkind expected'); +/** Decoder for `logkind` */ +export const jLogkind: Json.Decoder<logkind> = Json.jEnum(logkind); /** Natural order for `logkind` */ export const byLogkind: Compare.Order<logkind> = Compare.byEnum(logkind); @@ -132,7 +122,7 @@ const logkindTags_internal: Server.GetRequest<null,tag[]> = { kind: Server.RqKind.GET, name: 'kernel.services.logkindTags', input: Json.jNull, - output: Json.jList(jTag), + output: Json.jArray(jTag), signals: [], }; /** Registered tags for the above type. */ @@ -158,23 +148,19 @@ export interface messageData { fct?: Json.key<'#fct'>; } -/** Loose decoder for `messageData` */ -export const jMessageData: Json.Loose<messageData> = +/** Decoder for `messageData` */ +export const jMessageData: Json.Decoder<messageData> = Json.jObject({ - key: Json.jFail(Json.jKey<'#message'>('#message'),'#message expected'), - kind: jLogkindSafe, - plugin: Json.jFail(Json.jString,'String expected'), - message: Json.jFail(Json.jString,'String expected'), - category: Json.jString, - source: jSource, - marker: jMarker, - fct: Json.jKey<'#fct'>('#fct'), + key: Json.jKey<'#message'>('#message'), + kind: jLogkind, + plugin: Json.jString, + message: Json.jString, + category: Json.jOption(Json.jString), + source: Json.jOption(jSource), + marker: Json.jOption(jMarker), + fct: Json.jOption(Json.jKey<'#fct'>('#fct')), }); -/** Safe decoder for `messageData` */ -export const jMessageDataSafe: Json.Safe<messageData> = - Json.jFail(jMessageData,'MessageData expected'); - /** Natural order for `messageData` */ export const byMessageData: Compare.Order<messageData> = Compare.byFields @@ -215,10 +201,10 @@ const fetchMessage_internal: Server.GetRequest< name: 'kernel.services.fetchMessage', input: Json.jNumber, output: Json.jObject({ - pending: Json.jFail(Json.jNumber,'Number expected'), - updated: Json.jList(jMessageData), - removed: Json.jList(Json.jKey<'#message'>('#message')), - reload: Json.jFail(Json.jBoolean,'Boolean expected'), + pending: Json.jNumber, + updated: Json.jArray(jMessageData), + removed: Json.jArray(Json.jKey<'#message'>('#message')), + reload: Json.jBoolean, }), signals: [], }; @@ -254,19 +240,16 @@ export interface log { source?: source; } -/** Loose decoder for `log` */ -export const jLog: Json.Loose<log> = +/** Decoder for `log` */ +export const jLog: Json.Decoder<log> = Json.jObject({ - kind: jLogkindSafe, - plugin: Json.jFail(Json.jString,'String expected'), - message: Json.jFail(Json.jString,'String expected'), - category: Json.jString, - source: jSource, + kind: jLogkind, + plugin: Json.jString, + message: Json.jString, + category: Json.jOption(Json.jString), + source: Json.jOption(jSource), }); -/** Safe decoder for `log` */ -export const jLogSafe: Json.Safe<log> = Json.jFail(jLog,'Log expected'); - /** Natural order for `log` */ export const byLog: Compare.Order<log> = Compare.byFields @@ -293,7 +276,7 @@ const getLogs_internal: Server.GetRequest<null,log[]> = { kind: Server.RqKind.GET, name: 'kernel.services.getLogs', input: Json.jNull, - output: Json.jList(jLog), + output: Json.jArray(jLog), signals: [], }; /** Flush the last emitted logs since last call (max 100) */ diff --git a/ivette/src/frama-c/plugins/dive/api/index.ts b/ivette/src/frama-c/plugins/dive/api/index.ts index 78a1092d8ff..d3232121887 100644 --- a/ivette/src/frama-c/plugins/dive/api/index.ts +++ b/ivette/src/frama-c/plugins/dive/api/index.ts @@ -44,12 +44,8 @@ import { byMarker } from 'frama-c/kernel/api/ast'; //@ts-ignore import { jLocation } from 'frama-c/kernel/api/ast'; //@ts-ignore -import { jLocationSafe } from 'frama-c/kernel/api/ast'; -//@ts-ignore import { jMarker } from 'frama-c/kernel/api/ast'; //@ts-ignore -import { jMarkerSafe } from 'frama-c/kernel/api/ast'; -//@ts-ignore import { location } from 'frama-c/kernel/api/ast'; //@ts-ignore import { marker } from 'frama-c/kernel/api/ast'; @@ -62,13 +58,12 @@ export interface range { forward?: number; } -/** Loose decoder for `range` */ -export const jRange: Json.Loose<range> = - Json.jObject({ backward: Json.jNumber, forward: Json.jNumber,}); - -/** Safe decoder for `range` */ -export const jRangeSafe: Json.Safe<range> = - Json.jFail(jRange,'Range expected'); +/** Decoder for `range` */ +export const jRange: Json.Decoder<range> = + Json.jObject({ + backward: Json.jOption(Json.jNumber), + forward: Json.jOption(Json.jNumber), + }); /** Natural order for `range` */ export const byRange: Compare.Order<range> = @@ -86,13 +81,9 @@ export interface explorationWindow { horizon: range; } -/** Loose decoder for `explorationWindow` */ -export const jExplorationWindow: Json.Loose<explorationWindow> = - Json.jObject({ perception: jRangeSafe, horizon: jRangeSafe,}); - -/** Safe decoder for `explorationWindow` */ -export const jExplorationWindowSafe: Json.Safe<explorationWindow> = - Json.jFail(jExplorationWindow,'ExplorationWindow expected'); +/** Decoder for `explorationWindow` */ +export const jExplorationWindow: Json.Decoder<explorationWindow> = + Json.jObject({ perception: jRange, horizon: jRange,}); /** Natural order for `explorationWindow` */ export const byExplorationWindow: Compare.Order<explorationWindow> = @@ -105,12 +96,8 @@ export const byExplorationWindow: Compare.Order<explorationWindow> = /** A node identifier in the graph */ export type nodeId = number; -/** Loose decoder for `nodeId` */ -export const jNodeId: Json.Loose<nodeId> = Json.jNumber; - -/** Safe decoder for `nodeId` */ -export const jNodeIdSafe: Json.Safe<nodeId> = - Json.jFail(Json.jNumber,'Number expected'); +/** Decoder for `nodeId` */ +export const jNodeId: Json.Decoder<nodeId> = Json.jNumber; /** Natural order for `nodeId` */ export const byNodeId: Compare.Order<nodeId> = Compare.number; @@ -118,19 +105,13 @@ export const byNodeId: Compare.Order<nodeId> = Compare.number; /** A callsite */ export type callsite = { fun: string, instr: number | string }; -/** Loose decoder for `callsite` */ -export const jCallsite: Json.Loose<callsite> = +/** Decoder for `callsite` */ +export const jCallsite: Json.Decoder<callsite> = Json.jObject({ - fun: Json.jFail(Json.jString,'String expected'), - instr: Json.jFail( - Json.jUnion<number | string>( Json.jNumber, Json.jString,), - 'Union expected'), + fun: Json.jString, + instr: Json.jUnion<number | string>( Json.jNumber, Json.jString,), }); -/** Safe decoder for `callsite` */ -export const jCallsiteSafe: Json.Safe<callsite> = - Json.jFail(jCallsite,'Callsite expected'); - /** Natural order for `callsite` */ export const byCallsite: Compare.Order<callsite> = Compare.byFields @@ -142,12 +123,8 @@ export const byCallsite: Compare.Order<callsite> = /** The callstack context for a node */ export type callstack = callsite[]; -/** Safe decoder for `callstack` */ -export const jCallstackSafe: Json.Safe<callstack> = - Json.jArray(jCallsiteSafe); - -/** Loose decoder for `callstack` */ -export const jCallstack: Json.Loose<callstack> = Json.jTry(jCallstackSafe); +/** Decoder for `callstack` */ +export const jCallstack: Json.Decoder<callstack> = Json.jArray(jCallsite); /** Natural order for `callstack` */ export const byCallstack: Compare.Order<callstack> = @@ -156,16 +133,9 @@ export const byCallstack: Compare.Order<callstack> = /** The description of a node locality */ export type nodeLocality = { file: string, callstack?: callstack }; -/** Loose decoder for `nodeLocality` */ -export const jNodeLocality: Json.Loose<nodeLocality> = - Json.jObject({ - file: Json.jFail(Json.jString,'String expected'), - callstack: jCallstack, - }); - -/** Safe decoder for `nodeLocality` */ -export const jNodeLocalitySafe: Json.Safe<nodeLocality> = - Json.jFail(jNodeLocality,'NodeLocality expected'); +/** Decoder for `nodeLocality` */ +export const jNodeLocality: Json.Decoder<nodeLocality> = + Json.jObject({ file: Json.jString, callstack: Json.jOption(jCallstack),}); /** Natural order for `nodeLocality` */ export const byNodeLocality: Compare.Order<nodeLocality> = @@ -182,27 +152,22 @@ export type node = writes: location[], values?: string, range: number | string, type?: string }; -/** Loose decoder for `node` */ -export const jNode: Json.Loose<node> = +/** Decoder for `node` */ +export const jNode: Json.Decoder<node> = Json.jObject({ - id: jNodeIdSafe, - label: Json.jFail(Json.jString,'String expected'), - kind: Json.jFail(Json.jString,'String expected'), - locality: jNodeLocalitySafe, - is_root: Json.jFail(Json.jBoolean,'Boolean expected'), - backward_explored: Json.jFail(Json.jString,'String expected'), - forward_explored: Json.jFail(Json.jString,'String expected'), - writes: Json.jArray(jLocationSafe), - values: Json.jString, - range: Json.jFail( - Json.jUnion<number | string>( Json.jNumber, Json.jString,), - 'Union expected'), - type: Json.jString, + id: jNodeId, + label: Json.jString, + kind: Json.jString, + locality: jNodeLocality, + is_root: Json.jBoolean, + backward_explored: Json.jString, + forward_explored: Json.jString, + writes: Json.jArray(jLocation), + values: Json.jOption(Json.jString), + range: Json.jUnion<number | string>( Json.jNumber, Json.jString,), + type: Json.jOption(Json.jString), }); -/** Safe decoder for `node` */ -export const jNodeSafe: Json.Safe<node> = Json.jFail(jNode,'Node expected'); - /** Natural order for `node` */ export const byNode: Compare.Order<node> = Compare.byFields @@ -227,20 +192,16 @@ export const byNode: Compare.Order<node> = export type dependency = { id: number, src: nodeId, dst: nodeId, kind: string, origins: location[] }; -/** Loose decoder for `dependency` */ -export const jDependency: Json.Loose<dependency> = +/** Decoder for `dependency` */ +export const jDependency: Json.Decoder<dependency> = Json.jObject({ - id: Json.jFail(Json.jNumber,'Number expected'), - src: jNodeIdSafe, - dst: jNodeIdSafe, - kind: Json.jFail(Json.jString,'String expected'), - origins: Json.jArray(jLocationSafe), + id: Json.jNumber, + src: jNodeId, + dst: jNodeId, + kind: Json.jString, + origins: Json.jArray(jLocation), }); -/** Safe decoder for `dependency` */ -export const jDependencySafe: Json.Safe<dependency> = - Json.jFail(jDependency,'Dependency expected'); - /** Natural order for `dependency` */ export const byDependency: Compare.Order<dependency> = Compare.byFields @@ -256,16 +217,9 @@ export const byDependency: Compare.Order<dependency> = /** The whole graph being built */ export type graphData = { nodes: node[], deps: dependency[] }; -/** Loose decoder for `graphData` */ -export const jGraphData: Json.Loose<graphData> = - Json.jObject({ - nodes: Json.jArray(jNodeSafe), - deps: Json.jArray(jDependencySafe), - }); - -/** Safe decoder for `graphData` */ -export const jGraphDataSafe: Json.Safe<graphData> = - Json.jFail(jGraphData,'GraphData expected'); +/** Decoder for `graphData` */ +export const jGraphData: Json.Decoder<graphData> = + Json.jObject({ nodes: Json.jArray(jNode), deps: Json.jArray(jDependency),}); /** Natural order for `graphData` */ export const byGraphData: Compare.Order<graphData> = @@ -280,22 +234,17 @@ export type diffData = { root?: nodeId, add: { nodes: node[], deps: dependency[] }, sub: nodeId[] }; -/** Loose decoder for `diffData` */ -export const jDiffData: Json.Loose<diffData> = +/** Decoder for `diffData` */ +export const jDiffData: Json.Decoder<diffData> = Json.jObject({ - root: jNodeId, - add: Json.jFail( - Json.jObject({ - nodes: Json.jArray(jNodeSafe), - deps: Json.jArray(jDependencySafe), - }),'Record expected'), - sub: Json.jArray(jNodeIdSafe), + root: Json.jOption(jNodeId), + add: Json.jObject({ + nodes: Json.jArray(jNode), + deps: Json.jArray(jDependency), + }), + sub: Json.jArray(jNodeId), }); -/** Safe decoder for `diffData` */ -export const jDiffDataSafe: Json.Safe<diffData> = - Json.jFail(jDiffData,'DiffData expected'); - /** Natural order for `diffData` */ export const byDiffData: Compare.Order<diffData> = Compare.byFields diff --git a/ivette/src/frama-c/plugins/eva/api/general/index.ts b/ivette/src/frama-c/plugins/eva/api/general/index.ts index cf5797288c8..08a43ba5347 100644 --- a/ivette/src/frama-c/plugins/eva/api/general/index.ts +++ b/ivette/src/frama-c/plugins/eva/api/general/index.ts @@ -42,33 +42,25 @@ import { byMarker } from 'frama-c/kernel/api/ast'; //@ts-ignore import { jMarker } from 'frama-c/kernel/api/ast'; //@ts-ignore -import { jMarkerSafe } from 'frama-c/kernel/api/ast'; -//@ts-ignore import { marker } from 'frama-c/kernel/api/ast'; //@ts-ignore import { byTag } from 'frama-c/kernel/api/data'; //@ts-ignore import { jTag } from 'frama-c/kernel/api/data'; //@ts-ignore -import { jTagSafe } from 'frama-c/kernel/api/data'; -//@ts-ignore import { tag } from 'frama-c/kernel/api/data'; /** State of the computation of Eva Analysis. */ export type computationStateType = "not_computed" | "computing" | "computed"; -/** Loose decoder for `computationStateType` */ -export const jComputationStateType: Json.Loose<computationStateType> = +/** Decoder for `computationStateType` */ +export const jComputationStateType: Json.Decoder<computationStateType> = Json.jUnion<"not_computed" | "computing" | "computed">( Json.jTag("not_computed"), Json.jTag("computing"), Json.jTag("computed"), ); -/** Safe decoder for `computationStateType` */ -export const jComputationStateTypeSafe: Json.Safe<computationStateType> = - Json.jFail(jComputationStateType,'ComputationStateType expected'); - /** Natural order for `computationStateType` */ export const byComputationStateType: Compare.Order<computationStateType> = Compare.structural; @@ -109,12 +101,11 @@ const getCallers_internal: Server.GetRequest< kind: Server.RqKind.GET, name: 'plugins.eva.general.getCallers', input: Json.jKey<'#fct'>('#fct'), - output: Json.jList( - Json.jTry( - Json.jPair( - Json.jFail(Json.jKey<'#fct'>('#fct'),'#fct expected'), - Json.jFail(Json.jKey<'#stmt'>('#stmt'),'#stmt expected'), - ))), + output: Json.jArray( + Json.jPair( + Json.jKey<'#fct'>('#fct'), + Json.jKey<'#stmt'>('#stmt'), + )), signals: [], }; /** Get the list of call site of a function */ @@ -131,18 +122,13 @@ export interface functionsData { eva_analyzed?: boolean; } -/** Loose decoder for `functionsData` */ -export const jFunctionsData: Json.Loose<functionsData> = +/** Decoder for `functionsData` */ +export const jFunctionsData: Json.Decoder<functionsData> = Json.jObject({ - key: Json.jFail(Json.jKey<'#functions'>('#functions'), - '#functions expected'), - eva_analyzed: Json.jBoolean, + key: Json.jKey<'#functions'>('#functions'), + eva_analyzed: Json.jOption(Json.jBoolean), }); -/** Safe decoder for `functionsData` */ -export const jFunctionsDataSafe: Json.Safe<functionsData> = - Json.jFail(jFunctionsData,'FunctionsData expected'); - /** Natural order for `functionsData` */ export const byFunctionsData: Compare.Order<functionsData> = Compare.byFields @@ -175,10 +161,10 @@ const fetchFunctions_internal: Server.GetRequest< name: 'plugins.eva.general.fetchFunctions', input: Json.jNumber, output: Json.jObject({ - pending: Json.jFail(Json.jNumber,'Number expected'), - updated: Json.jList(jFunctionsData), - removed: Json.jList(Json.jKey<'#functions'>('#functions')), - reload: Json.jFail(Json.jBoolean,'Boolean expected'), + pending: Json.jNumber, + updated: Json.jArray(jFunctionsData), + removed: Json.jArray(Json.jKey<'#functions'>('#functions')), + reload: Json.jBoolean, }), signals: [], }; @@ -208,17 +194,13 @@ export interface deadCode { nonTerminating: marker[]; } -/** Loose decoder for `deadCode` */ -export const jDeadCode: Json.Loose<deadCode> = +/** Decoder for `deadCode` */ +export const jDeadCode: Json.Decoder<deadCode> = Json.jObject({ - unreachable: Json.jList(jMarker), - nonTerminating: Json.jList(jMarker), + unreachable: Json.jArray(jMarker), + nonTerminating: Json.jArray(jMarker), }); -/** Safe decoder for `deadCode` */ -export const jDeadCodeSafe: Json.Safe<deadCode> = - Json.jFail(jDeadCode,'DeadCode expected'); - /** Natural order for `deadCode` */ export const byDeadCode: Compare.Order<deadCode> = Compare.byFields @@ -257,13 +239,9 @@ export enum taintStatus { not_tainted = 'not_tainted', } -/** Loose decoder for `taintStatus` */ -export const jTaintStatus: Json.Loose<taintStatus> = Json.jEnum(taintStatus); - -/** Safe decoder for `taintStatus` */ -export const jTaintStatusSafe: Json.Safe<taintStatus> = - Json.jFail(Json.jEnum(taintStatus), - 'plugins.eva.general.taintStatus expected'); +/** Decoder for `taintStatus` */ +export const jTaintStatus: Json.Decoder<taintStatus> = + Json.jEnum(taintStatus); /** Natural order for `taintStatus` */ export const byTaintStatus: Compare.Order<taintStatus> = @@ -273,7 +251,7 @@ const taintStatusTags_internal: Server.GetRequest<null,tag[]> = { kind: Server.RqKind.GET, name: 'plugins.eva.general.taintStatusTags', input: Json.jNull, - output: Json.jList(jTag), + output: Json.jArray(jTag), signals: [], }; /** Registered tags for the above type. */ @@ -289,18 +267,14 @@ export interface propertiesData { taint: taintStatus; } -/** Loose decoder for `propertiesData` */ -export const jPropertiesData: Json.Loose<propertiesData> = +/** Decoder for `propertiesData` */ +export const jPropertiesData: Json.Decoder<propertiesData> = Json.jObject({ - key: Json.jFail(Json.jKey<'#property'>('#property'),'#property expected'), - priority: Json.jFail(Json.jBoolean,'Boolean expected'), - taint: jTaintStatusSafe, + key: Json.jKey<'#property'>('#property'), + priority: Json.jBoolean, + taint: jTaintStatus, }); -/** Safe decoder for `propertiesData` */ -export const jPropertiesDataSafe: Json.Safe<propertiesData> = - Json.jFail(jPropertiesData,'PropertiesData expected'); - /** Natural order for `propertiesData` */ export const byPropertiesData: Compare.Order<propertiesData> = Compare.byFields @@ -334,10 +308,10 @@ const fetchProperties_internal: Server.GetRequest< name: 'plugins.eva.general.fetchProperties', input: Json.jNumber, output: Json.jObject({ - pending: Json.jFail(Json.jNumber,'Number expected'), - updated: Json.jList(jPropertiesData), - removed: Json.jList(Json.jKey<'#property'>('#property')), - reload: Json.jFail(Json.jBoolean,'Boolean expected'), + pending: Json.jNumber, + updated: Json.jArray(jPropertiesData), + removed: Json.jArray(Json.jKey<'#property'>('#property')), + reload: Json.jBoolean, }), signals: [], }; @@ -383,15 +357,10 @@ export enum alarmCategory { other = 'other', } -/** Loose decoder for `alarmCategory` */ -export const jAlarmCategory: Json.Loose<alarmCategory> = +/** Decoder for `alarmCategory` */ +export const jAlarmCategory: Json.Decoder<alarmCategory> = Json.jEnum(alarmCategory); -/** Safe decoder for `alarmCategory` */ -export const jAlarmCategorySafe: Json.Safe<alarmCategory> = - Json.jFail(Json.jEnum(alarmCategory), - 'plugins.eva.general.alarmCategory expected'); - /** Natural order for `alarmCategory` */ export const byAlarmCategory: Compare.Order<alarmCategory> = Compare.byEnum(alarmCategory); @@ -400,7 +369,7 @@ const alarmCategoryTags_internal: Server.GetRequest<null,tag[]> = { kind: Server.RqKind.GET, name: 'plugins.eva.general.alarmCategoryTags', input: Json.jNull, - output: Json.jList(jTag), + output: Json.jArray(jTag), signals: [], }; /** Registered tags for the above type. */ @@ -410,18 +379,14 @@ export const alarmCategoryTags: Server.GetRequest<null,tag[]>= alarmCategoryTags export type statusesEntry = { valid: number, unknown: number, invalid: number }; -/** Loose decoder for `statusesEntry` */ -export const jStatusesEntry: Json.Loose<statusesEntry> = +/** Decoder for `statusesEntry` */ +export const jStatusesEntry: Json.Decoder<statusesEntry> = Json.jObject({ - valid: Json.jFail(Json.jNumber,'Number expected'), - unknown: Json.jFail(Json.jNumber,'Number expected'), - invalid: Json.jFail(Json.jNumber,'Number expected'), + valid: Json.jNumber, + unknown: Json.jNumber, + invalid: Json.jNumber, }); -/** Safe decoder for `statusesEntry` */ -export const jStatusesEntrySafe: Json.Safe<statusesEntry> = - Json.jFail(jStatusesEntry,'StatusesEntry expected'); - /** Natural order for `statusesEntry` */ export const byStatusesEntry: Compare.Order<statusesEntry> = Compare.byFields @@ -434,16 +399,9 @@ export const byStatusesEntry: Compare.Order<statusesEntry> = /** Alarm count for each alarm category. */ export type alarmEntry = { category: alarmCategory, count: number }; -/** Loose decoder for `alarmEntry` */ -export const jAlarmEntry: Json.Loose<alarmEntry> = - Json.jObject({ - category: jAlarmCategorySafe, - count: Json.jFail(Json.jNumber,'Number expected'), - }); - -/** Safe decoder for `alarmEntry` */ -export const jAlarmEntrySafe: Json.Safe<alarmEntry> = - Json.jFail(jAlarmEntry,'AlarmEntry expected'); +/** Decoder for `alarmEntry` */ +export const jAlarmEntry: Json.Decoder<alarmEntry> = + Json.jObject({ category: jAlarmCategory, count: Json.jNumber,}); /** Natural order for `alarmEntry` */ export const byAlarmEntry: Compare.Order<alarmEntry> = @@ -463,41 +421,28 @@ export type programStatsType = alarmsStatuses: statusesEntry, assertionsStatuses: statusesEntry, precondsStatuses: statusesEntry }; -/** Loose decoder for `programStatsType` */ -export const jProgramStatsType: Json.Loose<programStatsType> = +/** Decoder for `programStatsType` */ +export const jProgramStatsType: Json.Decoder<programStatsType> = Json.jObject({ - progFunCoverage: Json.jFail( - Json.jObject({ - reachable: Json.jFail(Json.jNumber, - 'Number expected'), - dead: Json.jFail(Json.jNumber,'Number expected'), - }),'Record expected'), - progStmtCoverage: Json.jFail( - Json.jObject({ - reachable: Json.jFail(Json.jNumber, - 'Number expected'), - dead: Json.jFail(Json.jNumber,'Number expected'), - }),'Record expected'), - progAlarms: Json.jList(jAlarmEntry), - evaEvents: Json.jFail( - Json.jObject({ - errors: Json.jFail(Json.jNumber,'Number expected'), - warnings: Json.jFail(Json.jNumber,'Number expected'), - }),'Record expected'), - kernelEvents: Json.jFail( - Json.jObject({ - errors: Json.jFail(Json.jNumber,'Number expected'), - warnings: Json.jFail(Json.jNumber,'Number expected'), - }),'Record expected'), - alarmsStatuses: jStatusesEntrySafe, - assertionsStatuses: jStatusesEntrySafe, - precondsStatuses: jStatusesEntrySafe, + progFunCoverage: Json.jObject({ + reachable: Json.jNumber, + dead: Json.jNumber, + }), + progStmtCoverage: Json.jObject({ + reachable: Json.jNumber, + dead: Json.jNumber, + }), + progAlarms: Json.jArray(jAlarmEntry), + evaEvents: Json.jObject({ errors: Json.jNumber, warnings: Json.jNumber,}), + kernelEvents: Json.jObject({ + errors: Json.jNumber, + warnings: Json.jNumber, + }), + alarmsStatuses: jStatusesEntry, + assertionsStatuses: jStatusesEntry, + precondsStatuses: jStatusesEntry, }); -/** Safe decoder for `programStatsType` */ -export const jProgramStatsTypeSafe: Json.Safe<programStatsType> = - Json.jFail(jProgramStatsType,'ProgramStatsType expected'); - /** Natural order for `programStatsType` */ export const byProgramStatsType: Compare.Order<programStatsType> = Compare.byFields @@ -569,23 +514,15 @@ export interface functionStatsData { alarmStatuses: statusesEntry; } -/** Loose decoder for `functionStatsData` */ -export const jFunctionStatsData: Json.Loose<functionStatsData> = +/** Decoder for `functionStatsData` */ +export const jFunctionStatsData: Json.Decoder<functionStatsData> = Json.jObject({ - key: Json.jFail(Json.jKey<'#fundec'>('#fundec'),'#fundec expected'), - coverage: Json.jFail( - Json.jObject({ - reachable: Json.jFail(Json.jNumber,'Number expected'), - dead: Json.jFail(Json.jNumber,'Number expected'), - }),'Record expected'), - alarmCount: Json.jList(jAlarmEntry), - alarmStatuses: jStatusesEntrySafe, + key: Json.jKey<'#fundec'>('#fundec'), + coverage: Json.jObject({ reachable: Json.jNumber, dead: Json.jNumber,}), + alarmCount: Json.jArray(jAlarmEntry), + alarmStatuses: jStatusesEntry, }); -/** Safe decoder for `functionStatsData` */ -export const jFunctionStatsDataSafe: Json.Safe<functionStatsData> = - Json.jFail(jFunctionStatsData,'FunctionStatsData expected'); - /** Natural order for `functionStatsData` */ export const byFunctionStatsData: Compare.Order<functionStatsData> = Compare.byFields @@ -626,10 +563,10 @@ const fetchFunctionStats_internal: Server.GetRequest< name: 'plugins.eva.general.fetchFunctionStats', input: Json.jNumber, output: Json.jObject({ - pending: Json.jFail(Json.jNumber,'Number expected'), - updated: Json.jList(jFunctionStatsData), - removed: Json.jList(Json.jKey<'#fundec'>('#fundec')), - reload: Json.jFail(Json.jBoolean,'Boolean expected'), + pending: Json.jNumber, + updated: Json.jArray(jFunctionStatsData), + removed: Json.jArray(Json.jKey<'#fundec'>('#fundec')), + reload: Json.jBoolean, }), signals: [], }; @@ -663,18 +600,9 @@ const getStates_internal: Server.GetRequest< > = { kind: Server.RqKind.GET, name: 'plugins.eva.general.getStates', - input: Json.jTry( - Json.jPair( - jMarkerSafe, - Json.jFail(Json.jBoolean,'Boolean expected'), - )), - output: Json.jList( - Json.jTry( - Json.jTriple( - Json.jFail(Json.jString,'String expected'), - Json.jFail(Json.jString,'String expected'), - Json.jFail(Json.jString,'String expected'), - ))), + input: Json.jPair( jMarker, Json.jBoolean,), + output: Json.jArray( + Json.jTriple( Json.jString, Json.jString, Json.jString,)), signals: [], }; /** Get the domain states about the given marker */ diff --git a/ivette/src/frama-c/plugins/eva/api/values/index.ts b/ivette/src/frama-c/plugins/eva/api/values/index.ts index c286426c70a..b713376b0b4 100644 --- a/ivette/src/frama-c/plugins/eva/api/values/index.ts +++ b/ivette/src/frama-c/plugins/eva/api/values/index.ts @@ -42,8 +42,6 @@ import { byMarker } from 'frama-c/kernel/api/ast'; //@ts-ignore import { jMarker } from 'frama-c/kernel/api/ast'; //@ts-ignore -import { jMarkerSafe } from 'frama-c/kernel/api/ast'; -//@ts-ignore import { marker } from 'frama-c/kernel/api/ast'; /** Emitted when EVA results has changed */ @@ -53,23 +51,18 @@ export const changed: Server.Signal = { export type callstack = Json.index<'#eva-callstack-id'>; -/** Loose decoder for `callstack` */ -export const jCallstack: Json.Loose<callstack> = +/** Decoder for `callstack` */ +export const jCallstack: Json.Decoder<callstack> = Json.jIndex<'#eva-callstack-id'>('#eva-callstack-id'); -/** Safe decoder for `callstack` */ -export const jCallstackSafe: Json.Safe<callstack> = - Json.jFail(Json.jIndex<'#eva-callstack-id'>('#eva-callstack-id'), - '#eva-callstack-id expected'); - /** Natural order for `callstack` */ export const byCallstack: Compare.Order<callstack> = Compare.number; const getCallstacks_internal: Server.GetRequest<marker[],callstack[]> = { kind: Server.RqKind.GET, name: 'plugins.eva.values.getCallstacks', - input: Json.jList(jMarker), - output: Json.jList(jCallstack), + input: Json.jArray(jMarker), + output: Json.jArray(jCallstack), signals: [], }; /** Callstacks for markers */ @@ -83,12 +76,12 @@ const getCallstackInfo_internal: Server.GetRequest< kind: Server.RqKind.GET, name: 'plugins.eva.values.getCallstackInfo', input: jCallstack, - output: Json.jList( + output: Json.jArray( Json.jObject({ - callee: Json.jFail(Json.jKey<'#fct'>('#fct'),'#fct expected'), - caller: Json.jKey<'#fct'>('#fct'), - stmt: Json.jKey<'#stmt'>('#stmt'), - rank: Json.jNumber, + callee: Json.jKey<'#fct'>('#fct'), + caller: Json.jOption(Json.jKey<'#fct'>('#fct')), + stmt: Json.jOption(Json.jKey<'#stmt'>('#stmt')), + rank: Json.jOption(Json.jNumber), })), signals: [], }; @@ -106,9 +99,7 @@ const getStmtInfo_internal: Server.GetRequest< kind: Server.RqKind.GET, name: 'plugins.eva.values.getStmtInfo', input: Json.jKey<'#stmt'>('#stmt'), - output: Json.jObject({ - rank: Json.jFail(Json.jNumber,'Number expected'), - fct: Json.jFail(Json.jKey<'#fct'>('#fct'),'#fct expected'), + output: Json.jObject({ rank: Json.jNumber, fct: Json.jKey<'#fct'>('#fct'), }), signals: [], }; @@ -127,12 +118,12 @@ const getProbeInfo_internal: Server.GetRequest< name: 'plugins.eva.values.getProbeInfo', input: jMarker, output: Json.jObject({ - condition: Json.jFail(Json.jBoolean,'Boolean expected'), - effects: Json.jFail(Json.jBoolean,'Boolean expected'), - rank: Json.jFail(Json.jNumber,'Number expected'), - stmt: Json.jKey<'#stmt'>('#stmt'), - code: Json.jString, - evaluable: Json.jFail(Json.jBoolean,'Boolean expected'), + condition: Json.jBoolean, + effects: Json.jBoolean, + rank: Json.jNumber, + stmt: Json.jOption(Json.jKey<'#stmt'>('#stmt')), + code: Json.jOption(Json.jString), + evaluable: Json.jBoolean, }), signals: [], }; @@ -153,33 +144,22 @@ export interface evaluation { pointedVars: [ string, marker ][]; } -/** Loose decoder for `evaluation` */ -export const jEvaluation: Json.Loose<evaluation> = +/** Decoder for `evaluation` */ +export const jEvaluation: Json.Decoder<evaluation> = Json.jObject({ - value: Json.jFail(Json.jString,'String expected'), - alarms: Json.jList( - Json.jTry( - Json.jPair( - Json.jFail( - Json.jUnion<"True" | "False" | "Unknown">( - Json.jTag("True"), - Json.jTag("False"), - Json.jTag("Unknown"), - ),'Union expected'), - Json.jFail(Json.jString,'String expected'), - ))), - pointedVars: Json.jList( - Json.jTry( - Json.jPair( - Json.jFail(Json.jString,'String expected'), - jMarkerSafe, - ))), + value: Json.jString, + alarms: Json.jArray( + Json.jPair( + Json.jUnion<"True" | "False" | "Unknown">( + Json.jTag("True"), + Json.jTag("False"), + Json.jTag("Unknown"), + ), + Json.jString, + )), + pointedVars: Json.jArray(Json.jPair( Json.jString, jMarker,)), }); -/** Safe decoder for `evaluation` */ -export const jEvaluationSafe: Json.Safe<evaluation> = - Json.jFail(jEvaluation,'Evaluation expected'); - /** Natural order for `evaluation` */ export const byEvaluation: Compare.Order<evaluation> = Compare.byFields @@ -197,12 +177,15 @@ const getValues_internal: Server.GetRequest< > = { kind: Server.RqKind.GET, name: 'plugins.eva.values.getValues', - input: Json.jObject({ callstack: jCallstack, target: jMarkerSafe,}), + input: Json.jObject({ + callstack: Json.jOption(jCallstack), + target: jMarker, + }), output: Json.jObject({ - vElse: jEvaluation, - vThen: jEvaluation, - vAfter: jEvaluation, - vBefore: jEvaluation, + vElse: Json.jOption(jEvaluation), + vThen: Json.jOption(jEvaluation), + vAfter: Json.jOption(jEvaluation), + vBefore: Json.jOption(jEvaluation), }), signals: [], }; diff --git a/ivette/src/frama-c/plugins/pivot/api/general/index.ts b/ivette/src/frama-c/plugins/pivot/api/general/index.ts index dc968c2c385..ab2c478b87e 100644 --- a/ivette/src/frama-c/plugins/pivot/api/general/index.ts +++ b/ivette/src/frama-c/plugins/pivot/api/general/index.ts @@ -41,13 +41,9 @@ import * as State from 'frama-c/states'; /** State of the pivot table source data. */ export type tableStateType = string[][]; -/** Safe decoder for `tableStateType` */ -export const jTableStateTypeSafe: Json.Safe<tableStateType> = - Json.jArray(Json.jArray(Json.jFail(Json.jString,'String expected'))); - -/** Loose decoder for `tableStateType` */ -export const jTableStateType: Json.Loose<tableStateType> = - Json.jTry(jTableStateTypeSafe); +/** Decoder for `tableStateType` */ +export const jTableStateType: Json.Decoder<tableStateType> = + Json.jArray(Json.jArray(Json.jString)); /** Natural order for `tableStateType` */ export const byTableStateType: Compare.Order<tableStateType> = diff --git a/ivette/src/frama-c/plugins/studia/api/studia/index.ts b/ivette/src/frama-c/plugins/studia/api/studia/index.ts index f0e0e32becc..54b71933609 100644 --- a/ivette/src/frama-c/plugins/studia/api/studia/index.ts +++ b/ivette/src/frama-c/plugins/studia/api/studia/index.ts @@ -42,8 +42,6 @@ import { byMarker } from 'frama-c/kernel/api/ast'; //@ts-ignore import { jMarker } from 'frama-c/kernel/api/ast'; //@ts-ignore -import { jMarkerSafe } from 'frama-c/kernel/api/ast'; -//@ts-ignore import { marker } from 'frama-c/kernel/api/ast'; /** Statements that read or write a location. */ @@ -54,27 +52,13 @@ export interface effects { indirect: [ Json.key<'#fct'>, marker ][]; } -/** Loose decoder for `effects` */ -export const jEffects: Json.Loose<effects> = +/** Decoder for `effects` */ +export const jEffects: Json.Decoder<effects> = Json.jObject({ - direct: Json.jList( - Json.jTry( - Json.jPair( - Json.jFail(Json.jKey<'#fct'>('#fct'),'#fct expected'), - jMarkerSafe, - ))), - indirect: Json.jList( - Json.jTry( - Json.jPair( - Json.jFail(Json.jKey<'#fct'>('#fct'),'#fct expected'), - jMarkerSafe, - ))), + direct: Json.jArray(Json.jPair( Json.jKey<'#fct'>('#fct'), jMarker,)), + indirect: Json.jArray(Json.jPair( Json.jKey<'#fct'>('#fct'), jMarker,)), }); -/** Safe decoder for `effects` */ -export const jEffectsSafe: Json.Safe<effects> = - Json.jFail(jEffects,'Effects expected'); - /** Natural order for `effects` */ export const byEffects: Compare.Order<effects> = Compare.byFields diff --git a/ivette/src/frama-c/server.ts b/ivette/src/frama-c/server.ts index d0ade05e197..510cad2e81f 100644 --- a/ivette/src/frama-c/server.ts +++ b/ivette/src/frama-c/server.ts @@ -730,9 +730,9 @@ export interface Request<Kd extends RqKind, In, Out> { /** The request full name. */ name: string; /** Encoder of input parameters. */ - input: Json.Loose<In>; + input: Json.Decoder<In>; /** Decoder of output parameters. */ - output: Json.Loose<Out>; + output: Json.Decoder<Out>; /** Signals the request depends on */ signals: Array<Signal>; } diff --git a/ivette/src/renderer/Laboratory.tsx b/ivette/src/renderer/Laboratory.tsx index d530a3baf67..a944186dcd5 100644 --- a/ivette/src/renderer/Laboratory.tsx +++ b/ivette/src/renderer/Laboratory.tsx @@ -268,13 +268,13 @@ function CustomViews(props: CustomViewsProps): JSX.Element { const { settings, shape, setShape, views: libViews } = props; const [local, setLocal] = Settings.useWindowSettings<CustomViewsSettings>( settings, - Json.identity as Json.Loose<CustomViewsSettings & Json.json>, // Clearly abusive conversion, a real decoder is needed + Json.identity as Json.Decoder<CustomViewsSettings & Json.json>, // Clearly abusive conversion, a real decoder is needed {}, ); const [customs, setCustoms] = Settings.useLocalStorage<{ [id: string]: View }>( 'frama-c.labview', - Json.identity as Json.Loose<{ [id: string]: View } & Json.json>, // Clearly abusive conversion, a real decoder is needed + Json.identity as Json.Decoder<{ [id: string]: View } & Json.json>, // Clearly abusive conversion, a real decoder is needed {}, ); const [edited, setEdited] = React.useState<string>(); diff --git a/src/plugins/api-generator/api_generator.ml b/src/plugins/api-generator/api_generator.ml index 58e8852eef6..4bfa7b77d4d 100644 --- a/src/plugins/api-generator/api_generator.ml +++ b/src/plugins/api-generator/api_generator.ml @@ -108,7 +108,7 @@ let makeJtype ?self ~names = Pretty_utils.pp_list ~pre:"@[<hov 0>" ~sep:" |@ " ~suf:"@]" protect fmt js | Jrecord fjs -> Pretty_utils.pp_list ~pre:"@[<hov 2>{ " ~sep:",@ " ~suf:"@ }@]" field fmt fjs - | Jarray js | Jlist js -> Format.fprintf fmt "%a[]" protect js + | Jarray js -> Format.fprintf fmt "%a[]" protect js and protect fmt js = match js with | Junion _ | Joption _ -> Format.fprintf fmt "@[<hov 2>(%a)@]" pp js | _ -> pp fmt js @@ -132,12 +132,6 @@ let jcall names fmt id = try Format.pp_print_string fmt (Pkg.IdMap.find id names) with Not_found -> Self.abort "Undefined identifier '%a'" Pkg.pp_ident id -let jsafe ~safe msg pp fmt d = - if safe then - Format.fprintf fmt "@[<hov 2>Json.jFail(@,%a,@,'%s expected')@]" pp d msg - else - pp fmt d - let jtry ~safe pp fmt d = if safe then pp fmt d @@ -146,25 +140,25 @@ let jtry ~safe pp fmt d = let jenum names fmt id = Format.fprintf fmt "Json.jEnum(%a)" (jcall names) id -let junion ~jtype ~makeLoose fmt jts = +let junion ~jtype ~make fmt jts = begin Format.fprintf fmt "@[<hv 0>@[<hv 2>Json.jUnion<%a>(" jtype (Pkg.Junion jts) ; List.iter - (fun js -> Format.fprintf fmt "@ @[<hov 2>%a@]," makeLoose js) jts ; + (fun js -> Format.fprintf fmt "@ @[<hov 2>%a@]," make js) jts ; Format.fprintf fmt "@]@,)@]" ; end -let jrecord ~makeSafe fmt jts = +let jrecord ~make fmt jts = begin Format.fprintf fmt "@[<hv 0>@[<hv 2>Json.jObject({" ; List.iter (fun (fd,js) -> - Format.fprintf fmt "@ @[<hov 2>%s: %a@]," fd makeSafe js) jts ; + Format.fprintf fmt "@ @[<hov 2>%s: %a@]," fd make js) jts ; Format.fprintf fmt "@]@,})@]" ; end -let jtuple ~makeSafe fmt jts = +let jtuple ~make fmt jts = begin let name = match List.length jts with | 2 -> "jPair" @@ -175,58 +169,41 @@ let jtuple ~makeSafe fmt jts = in Format.fprintf fmt "@[<hv 0>@[<hv 2>Json.%s(" name ; List.iter - (fun js -> Format.fprintf fmt "@ @[<hov 2>%a@]," makeSafe js) jts ; + (fun js -> Format.fprintf fmt "@ @[<hov 2>%a@]," make js) jts ; Format.fprintf fmt "@]@,)@]" ; end -let rec makeDecoder ~safe ?self ~names fmt js = +let rec makeDecoder ?self ~names fmt js = let open Pkg in - let makeSafe = makeDecoder ?self ~names ~safe:true in - let makeLoose = makeDecoder ?self ~names ~safe:false in + let make = makeDecoder ?self ~names in match js with | Jany -> jprim fmt "jAny" | Jnull -> jprim fmt "jNull" - | Jboolean -> jsafe ~safe "Boolean" jprim fmt "jBoolean" - | Jnumber -> jsafe ~safe "Number" jprim fmt "jNumber" - | Jstring | Jalpha -> jsafe ~safe "String" jprim fmt "jString" + | Jboolean -> jprim fmt "jBoolean" + | Jnumber -> jprim fmt "jNumber" + | Jstring | Jalpha -> jprim fmt "jString" | Jtag a -> Format.fprintf fmt "Json.jTag(\"%s\")" a - | Jkey kd -> jsafe ~safe ("#" ^ kd) jkey fmt kd - | Jindex kd -> jsafe ~safe ("#" ^ kd) jindex fmt kd - | Jdata id -> jcall names fmt (Pkg.Derived.decode ~safe id) - | Jenum id -> jsafe ~safe (Pkg.name_of_ident id) (jenum names) fmt id - | Jself -> jcall names fmt (Pkg.Derived.decode ~safe (getSelf self)) - | Joption js -> makeLoose fmt js + | Jkey kd -> jkey fmt kd + | Jindex kd -> jindex fmt kd + | Jdata id -> jcall names fmt (Pkg.Derived.decode id) + | Jenum id -> jenum names fmt id + | Jself -> jcall names fmt (Pkg.Derived.decode (getSelf self)) + | Joption js -> + Format.fprintf fmt "@[<hov 2>Json.jOption(@,%a)@]" make js | Jdict js -> - Format.fprintf fmt "@[<hov 2>Json.jDict(@,%a)@]" makeLoose js - | Jlist js -> - Format.fprintf fmt "@[<hov 2>Json.jList(@,%a)@]" makeLoose js + Format.fprintf fmt "@[<hov 2>Json.jDict(@,%a)@]" make js | Jarray js -> - if safe - then Format.fprintf fmt "@[<hov 2>Json.jArray(%a)@]" makeSafe js - else Format.fprintf fmt "@[<hov 2>Json.jTry(jArray(%a))@]" makeSafe js + Format.fprintf fmt "@[<hov 2>Json.jArray(@,%a)@]" make js | Junion jts -> let jtype = makeJtype ?self ~names in - jsafe ~safe "Union" (junion ~jtype ~makeLoose) fmt jts - | Jrecord jfs -> jsafe ~safe "Record" (jrecord ~makeSafe) fmt jfs - | Jtuple jts -> jtry ~safe (jtuple ~makeSafe) fmt jts + junion ~jtype ~make fmt jts + | Jrecord jfs -> jrecord ~make fmt jfs + | Jtuple jts -> jtuple ~make fmt jts let makeLooseNeedSafe = function | Pkg.Jtuple _ | Pkg.Jarray _ -> true | _ -> false -let makeRootDecoder ~safe ~self ~names fmt js = - let open Pkg in - match js with - | Joption _ | Jdict _ | Jlist _ when safe -> - jcall names fmt (Pkg.Derived.loose self) - | Jtuple _ | Jarray _ when not safe -> - Format.fprintf fmt "Json.jTry(%a)" - (jcall names) (Pkg.Derived.safe self) - | Junion _ | Jrecord _ when safe -> - Format.fprintf fmt "Json.jFail(%a,'%s expected')" - (jcall names) (Pkg.Derived.loose self) - (String.capitalize_ascii self.name) - | _ -> makeDecoder ~safe ~self ~names fmt js (* -------------------------------------------------------------------------- *) (* --- Parameter Decoder --- *) @@ -254,7 +231,7 @@ let makeOrder ~self ~names fmt js = Format.fprintf fmt "@[<hov 2>Compare.defined(@,%a)@]" pp js | Jenum id -> Format.fprintf fmt "@[<hov 2>Compare.byEnum(@,%a)@]" (jcall names) id - | Jlist js | Jarray js -> + | Jarray js -> Format.fprintf fmt "@[<hov 2>Compare.array(@,%a)@]" pp js | Jtuple jts -> let name = match List.length jts with @@ -341,7 +318,7 @@ let makeDeclaration fmt names d = let prefix = String.capitalize_ascii (String.lowercase_ascii kind) in let input = typeOfParam rq.rq_input in let output = typeOfParam rq.rq_output in - let makeParam fmt js = makeDecoder ~safe:false ~names fmt js in + let makeParam fmt js = makeDecoder ~names fmt js in Format.fprintf fmt "@[<hv 2>const %s_internal: Server.%sRequest<@,%a,@,%a@,>@] = {@\n" self.name prefix jtype input jtype output ; @@ -416,19 +393,12 @@ let makeDeclaration fmt names d = "@[<hv 2>export const %s: State.Array<@,%a,@,%a@,>@] = %s_internal;@\n" self.name jtype jkey jtype jrow self.name ; - | D_safe(id,js) -> - makeDescr fmt d.d_descr ; - Format.fprintf fmt - "@[<hov 2>@[<hv 0>export const %s: Json.Safe<@,%a@,>@] =@ %a;@]\n" - self.name (jcall names) id - (makeRecursive (makeRootDecoder ~safe:true ~self:id ~names)) js - - | D_loose(id,js) -> + | D_decoder(id,js) -> makeDescr fmt d.d_descr ; Format.fprintf fmt - "@[<hov 2>@[<hv 0>export const %s: Json.Loose<@,%a@,>@] =@ %a;@]\n" + "@[<hov 2>@[<hv 0>export const %s: Json.Decoder<@,%a@,>@] =@ %a;@]\n" self.name (jcall names) id - (makeRecursive (makeRootDecoder ~safe:false ~self:id ~names)) js + (makeRecursive (makeDecoder ~self:id ~names)) js | D_order(id,js) -> makeDescr fmt d.d_descr ; @@ -449,8 +419,6 @@ type ranking = { let depends d = match d.Pkg.d_kind with - | D_loose(id,t) when makeLooseNeedSafe t -> [Pkg.Derived.safe id] - | D_safe(id,t) when not (makeLooseNeedSafe t) -> [Pkg.Derived.loose id] | D_value _ -> let id = d.d_ident in [ @@ -469,8 +437,7 @@ let depends d = let data = Pkg.Derived.data id in [ data ; - Pkg.Derived.loose data ; - Pkg.Derived.safe data ; + Pkg.Derived.decode data ; Pkg.Derived.order data ; Pkg.Derived.signal id ; Pkg.Derived.reload id ; diff --git a/src/plugins/eva/api/general_requests.ml b/src/plugins/eva/api/general_requests.ml index af6c92b62ae..357298d59aa 100644 --- a/src/plugins/eva/api/general_requests.ml +++ b/src/plugins/eva/api/general_requests.ml @@ -509,7 +509,7 @@ end module Alarms = struct type t = (AlarmCategory.t * int) list - let jtype = Package.Jlist AlarmEntry.jtype + let jtype = Package.Jarray AlarmEntry.jtype let to_json x = `List (List.map AlarmEntry.to_json x) end diff --git a/src/plugins/eva/api/values_request.ml b/src/plugins/eva/api/values_request.ml index 8714daa8f22..032d9776bc8 100644 --- a/src/plugins/eva/api/values_request.ml +++ b/src/plugins/eva/api/values_request.ml @@ -208,7 +208,7 @@ module Jcalls : Request.Output with type t = callstack = struct type t = callstack - let jtype = Package.(Jlist (Jrecord [ + let jtype = Package.(Jarray (Jrecord [ "callee" , Jkf.jtype ; "caller" , Joption Jkf.jtype ; "stmt" , Joption Jstmt.jtype ; diff --git a/src/plugins/server/data.ml b/src/plugins/server/data.ml index 8b9722ba5d0..eda26bfe758 100644 --- a/src/plugins/server/data.ml +++ b/src/plugins/server/data.ml @@ -64,12 +64,9 @@ let package = Package.package ~name:"data" ~title:"Informations" () let derived ~package ~id jtype = let module Md = Markdown in begin - declare ~package ~name:(Derived.safe id).name - ~descr:(Md.plain "Safe decoder for" @ Md.code id.name) - (D_safe(id,jtype)) ; - declare ~package ~name:(Derived.loose id).name - ~descr:(Md.plain "Loose decoder for" @ Md.code id.name) - (D_loose(id,jtype)) ; + declare ~package ~name:(Derived.decode id).name + ~descr:(Md.plain "Decoder for" @ Md.code id.name) + (D_decoder(id,jtype)) ; declare ~package ~name:(Derived.order id).name ~descr:(Md.plain "Natural order for" @ Md.code id.name) (D_order(id,jtype)) ; @@ -130,14 +127,6 @@ end (* -------------------------------------------------------------------------- *) module Jlist(A : S) : S with type t = A.t list = -struct - type t = A.t list - let jtype = Jlist A.jtype - let to_json xs = `List (List.map A.to_json xs) - let of_json js = List.map A.of_json (Ju.to_list js) -end - -module Jalist(A : S) : S with type t = A.t list = struct type t = A.t list let jtype = Jarray A.jtype @@ -239,7 +228,7 @@ struct "Rich text format uses `[tag; …text ]` to apply \ the tag `tag` to the enclosed text. \ Empty tag `\"\"` can also used to simply group text together." in - let jdef = Junion [ Jnull; Jstring; Jlist Jself ] in + let jdef = Junion [ Jnull; Jstring; Jarray Jself ] in declare ~package ~name:"text" ~descr jdef end @@ -284,7 +273,7 @@ let jlist (type a) (d : a data) : a list data = (module A : S with type t = a list) let jalist (type a) (d : a data) : a list data = - let module A = Jalist(val d) in + let module A = Jlist(val d) in (module A : S with type t = a list) let jarray (type a) (d : a data) : a array data = diff --git a/src/plugins/server/data.mli b/src/plugins/server/data.mli index 87305705e39..cd056414d54 100644 --- a/src/plugins/server/data.mli +++ b/src/plugins/server/data.mli @@ -99,7 +99,6 @@ module Joption(A : S) : S with type t = A.t option module Jpair(A : S)(B : S) : S with type t = A.t * B.t module Jtriple(A : S)(B : S)(C : S) : S with type t = A.t * B.t * C.t module Jlist(A : S) : S with type t = A.t list -module Jalist(A : S) : S with type t = A.t list module Jarray(A : S) : S with type t = A.t array (* -------------------------------------------------------------------------- *) diff --git a/src/plugins/server/package.ml b/src/plugins/server/package.ml index 07150d8d185..feb0f41fcc8 100644 --- a/src/plugins/server/package.ml +++ b/src/plugins/server/package.ml @@ -171,7 +171,6 @@ type jtype = | Jindex of string (* kind of an integer used for indexing *) | Joption of jtype | Jdict of jtype (* dictionaries *) - | Jlist of jtype (* order does not matter *) | Jarray of jtype (* order matters *) | Jtuple of jtype list | Junion of jtype list @@ -221,8 +220,7 @@ type declKindInfo = | D_value of jtype | D_state of jtype | D_array of arrayInfo (* key kind *) - | D_safe of ident * jtype (* safe decoder *) - | D_loose of ident * jtype (* loose decoder *) + | D_decoder of ident * jtype | D_order of ident * jtype (* natural ordering *) type declInfo = { @@ -278,9 +276,7 @@ struct let fetch id = derived ~prefix:"fetch" id let reload id = derived ~prefix:"reload" id let order id = derived ~prefix:"by" id - let loose id = derived ~prefix:"j" id - let safe id = derived ~prefix:"j" ~suffix:"Safe" id - let decode ~safe:ok id = if ok then safe id else loose id + let decode id = derived ~prefix:"j" id end (* -------------------------------------------------------------------------- *) @@ -292,21 +288,20 @@ let rec isRecursive = function | Jdata _ | Jenum _ | Jany | Jnull | Jboolean | Jnumber | Jstring | Jalpha | Jkey _ | Jindex _ | Jtag _ -> false - | Joption js | Jdict js | Jarray js | Jlist js -> isRecursive js + | Joption js | Jdict js | Jarray js -> isRecursive js | Jtuple js | Junion js -> List.exists isRecursive js | Jrecord fjs -> List.exists (fun (_,js) -> isRecursive js) fjs let rec visit_jtype fn = function | Jany | Jself | Jnull | Jboolean | Jnumber | Jstring | Jalpha | Jkey _ | Jindex _ | Jtag _ -> () - | Joption js | Jdict js | Jarray js | Jlist js -> visit_jtype fn js + | Joption js | Jdict js | Jarray js -> visit_jtype fn js | Jtuple js | Junion js -> List.iter (visit_jtype fn) js | Jrecord fjs -> List.iter (fun (_,js) -> visit_jtype fn js) fjs | Jdata id | Jenum id -> begin fn id ; - fn (Derived.safe id) ; - fn (Derived.loose id) ; + fn (Derived.decode id) ; fn (Derived.order id) ; end @@ -322,7 +317,7 @@ let visit_request f { rq_input ; rq_output } = let visit_dkind f = function | D_signal | D_enum _ | D_array _ -> () | D_type js | D_state js | D_value js -> visit_jtype f js - | D_loose(id,js) | D_safe(id,js) | D_order(id,js) -> f id ; visit_jtype f js + | D_decoder (id,js) | D_order(id,js) -> f id ; visit_jtype f js | D_record fds -> List.iter (visit_field f) fds | D_request rq -> visit_request f rq @@ -470,7 +465,7 @@ let rec md_jtype pp = function | Joption js -> protect pp js @ Md.code "?" | Jtuple js -> Md.code "[" @ md_jlist pp "," js @ Md.code "]" | Junion js -> md_jlist pp "|" js - | Jarray js | Jlist js -> protect pp js @ Md.code "[]" + | Jarray js -> protect pp js @ Md.code "[]" | Jrecord fjs -> Md.code "{" @ fields pp fjs @ Md.code "}" | Jdict js -> Md.code "{[key]:" @ md_jtype pp js @ Md.code "}" diff --git a/src/plugins/server/package.mli b/src/plugins/server/package.mli index 56b0f3a34c0..55023a1b939 100644 --- a/src/plugins/server/package.mli +++ b/src/plugins/server/package.mli @@ -39,7 +39,6 @@ type jtype = | Jindex of string (** kind of an integer used for indexing *) | Joption of jtype | Jdict of jtype (** dictionaries *) - | Jlist of jtype (** order does not matter *) | Jarray of jtype (** order matters *) | Jtuple of jtype list | Junion of jtype list @@ -85,8 +84,7 @@ type declKindInfo = | D_value of jtype | D_state of jtype | D_array of arrayInfo - | D_safe of ident * jtype (* safe decoder *) - | D_loose of ident * jtype (* loose decoder *) + | D_decoder of ident * jtype | D_order of ident * jtype (* natural ordering *) type declInfo = { @@ -127,10 +125,8 @@ sig val data : ident -> ident val fetch : ident -> ident val reload : ident -> ident - val safe : ident -> ident - val loose : ident -> ident val order : ident -> ident - val decode : safe:bool -> ident -> ident + val decode : ident -> ident end (* -------------------------------------------------------------------------- *) diff --git a/src/plugins/server/server_doc.ml b/src/plugins/server/server_doc.ml index a1c14afd4fd..d2ba06ba700 100644 --- a/src/plugins/server/server_doc.ml +++ b/src/plugins/server/server_doc.ml @@ -134,7 +134,7 @@ let kind_of_decl = function | D_request { rq_kind=`GET } -> "GET" | D_request { rq_kind=`SET } -> "SET" | D_request { rq_kind=`EXEC } -> "EXEC" - | D_loose _ | D_safe _ | D_order _ -> assert false + | D_decoder _ | D_order _ -> assert false let pp_for ?decl names = let self = @@ -165,7 +165,7 @@ let md_signals signals = let descr_of_decl names decl = match decl.d_kind with - | D_safe _ | D_loose _ | D_order _ -> assert false + | D_decoder _ | D_order _ -> assert false | D_signal -> [] | D_state _ -> [] (* TBC *) | D_value _ -> [] (* TBC *) @@ -191,7 +191,7 @@ let descr_of_decl names decl = let declaration page names decl = match decl.d_kind with - | D_safe _ | D_loose _ | D_order _ -> () + | D_decoder _ | D_order _ -> () | _ -> let name = decl.d_ident.name in let fullname = name_of_ident decl.d_ident in -- GitLab