diff --git a/ivette/api/dive.ts b/ivette/api/dive.ts index 0e8f18121069d8f9902b039ca76d81442185c6ce..d00d62b0cba5e65d9b258fac46bf7a162d491d6e 100644 --- a/ivette/api/dive.ts +++ b/ivette/api/dive.ts @@ -1,6 +1,7 @@ /* --- Generated Frama-C Server API --- */ -/** Dive Services +/** + Dive Services @packageDocumentation @module frama-c/dive */ @@ -17,6 +18,18 @@ export interface variableName { varName: string; } +/** Safe decoder for `variableName` */ +export const jVariableNameSafe: Json.Safe<variableName> = + Json.jObject({ + funName: Json.jString, + varName: Json.jFail(Json.jString,'String expected'), + }); + +/** Loose decoder for `variableName` */ +export const jVariableName: Json.Loose<variableName> = + Json.jTry(jVariableNameSafe); + +/** Natural order for `variableName` */ /** Retrieve the whole graph */ export const graph: Server.GetRequest = { @@ -24,44 +37,40 @@ export const graph: Server.GetRequest = { name: 'dive.graph', }; - /** Erase the graph and start over with an empty one */ export const clear: Server.ExecRequest = { kind: Server.RqKind.EXEC, name: 'dive.clear', }; - /** Add a variable to the graph */ export const addVar: Server.ExecRequest = { kind: Server.RqKind.EXEC, name: 'dive.addVar', }; - /** Add all alarms of the given function */ export const addFunctionAlarms: Server.ExecRequest = { kind: Server.RqKind.EXEC, name: 'dive.addFunctionAlarms', }; - /** Explore the graph starting from an existing vertex */ export const explore: Server.ExecRequest = { kind: Server.RqKind.EXEC, name: 'dive.explore', }; - /** Show the dependencies of an existing vertex */ export const show: Server.ExecRequest = { kind: Server.RqKind.EXEC, name: 'dive.show', }; - /** Hide the dependencies of an existing vertex */ export const hide: Server.ExecRequest = { kind: Server.RqKind.EXEC, name: 'dive.hide', }; + +/* ------------------------------------- */ diff --git a/ivette/api/kernel/ast.ts b/ivette/api/kernel/ast.ts index 3bc9a01edcc37fad1bdbabcd4dd2199059519ee8..52d70d3f034154cadebaaa7e7821f1fe956009cc 100644 --- a/ivette/api/kernel/ast.ts +++ b/ivette/api/kernel/ast.ts @@ -1,23 +1,23 @@ /* --- Generated Frama-C Server API --- */ -/** Ast Services +/** + Ast Services @packageDocumentation @module frama-c/kernel/ast */ import * as Json from 'dome/data/json'; import * as Server from 'frama-c/server'; + import { tag } from 'api/kernel/data'; import { text } from 'api/kernel/data'; - /** Ensures that AST is computed */ export const compute: Server.ExecRequest = { kind: Server.RqKind.EXEC, name: 'kernel.ast.compute', }; - /** Marker kind */ export enum markerKind { /** Expression */ @@ -40,27 +40,35 @@ export enum markerKind { property = 'property'; } +/** Safe decoder for `markerKind` */ +export const jMarkerKindSafe: Json.Safe<markerKind> = + Json.jFail(Json.jEnum(markerKind),'kernel.ast.markerKind expected'); -/** Returns all registered tags for the above type. */ +/** Loose decoder for `markerKind` */ +export const jMarkerKind: Json.Loose<markerKind> = Json.jEnum(markerKind); + +/** Natural order for `markerKind` */ + +/** Registered tags for the above type. */ export const markerKindTags: Server.GetRequest = { kind: Server.RqKind.GET, name: 'kernel.ast.markerKindTags', }; - /** Markers data */ - - -/** Signal for array [`markerData`](#markerdata) - */ -export const markerDataSig: Server.Signal = { - name: 'kernel.ast.markerDataSig', +export const markerData: State.Array<'markerData',markerDataData> = { + signal: signalMarkerData, + fetch: fetchMarkerData, + reload: reloadMarkerData, }; +/** Signal for array [`markerData`](#markerdata) */ +export const signalMarkerData: Server.Signal = { + name: 'kernel.ast.signalMarkerData', +}; -/** Data rows for array [`markerData`](#markerdata) - */ -export interface markerDataRow { +/** Data for array rows [`markerData`](#markerdata) */ +export interface markerDataData { /** Entry identifier. */ key: Json.Key<'markerData'>; /** Marker kind */ @@ -71,28 +79,42 @@ export interface markerDataRow { descr: string; } - -/** Data fetcher for array [`markerData`](#markerdata) - */ -export const markerDataFetch: Server.GetRequest = { +/** Data fetcher for array [`markerData`](#markerdata) */ +export const fetchMarkerData: Server.GetRequest = { kind: Server.RqKind.GET, - name: 'kernel.ast.markerDataFetch', + name: 'kernel.ast.fetchMarkerData', }; - -/** Force full reload for array [`markerData`](#markerdata) - */ -export const markerDataReload: Server.GetRequest = { +/** Force full reload for array [`markerData`](#markerdata) */ +export const reloadMarkerData: Server.GetRequest = { kind: Server.RqKind.GET, - name: 'kernel.ast.markerDataReload', + name: 'kernel.ast.reloadMarkerData', }; - /** Localizable AST markers */ export type marker = Json.Key<'stmt'> | Json.Key<'decl'> | Json.Key<'lval'> | Json.Key<'expr'> | Json.Key<'term'> | Json.Key<'global'> | Json.Key<'property'>; +/** Safe decoder for `marker` */ +export const jMarkerSafe: Json.Safe<marker> = + Json.jFail(jMarker,'Marker expected'); + +/** Loose decoder for `marker` */ +export const jMarker: Json.Loose<marker> = + Json.jUnion<Json.Key<'stmt'> | Json.Key<'decl'> | Json.Key<'lval'> | + Json.Key<'expr'> | Json.Key<'term'> | Json.Key<'global'> | + Json.Key<'property'>>( + Json.jKey('stmt'), + Json.jKey('decl'), + Json.jKey('lval'), + Json.jKey('expr'), + Json.jKey('term'), + Json.jKey('global'), + Json.jKey('property'), + ); + +/** Natural order for `marker` */ /** Collect all functions in the AST */ export const getFunctions: Server.GetRequest = { @@ -100,27 +122,26 @@ export const getFunctions: Server.GetRequest = { name: 'kernel.ast.getFunctions', }; - /** Print the AST of a function */ export const printFunction: Server.GetRequest = { kind: Server.RqKind.GET, name: 'kernel.ast.printFunction', }; - /** AST Functions */ - - -/** Signal for array [`functions`](#functions) - */ -export const functionsSig: Server.Signal = { - name: 'kernel.ast.functionsSig', +export const functions: State.Array<'functions',functionsData> = { + signal: signalFunctions, + fetch: fetchFunctions, + reload: reloadFunctions, }; +/** Signal for array [`functions`](#functions) */ +export const signalFunctions: Server.Signal = { + name: 'kernel.ast.signalFunctions', +}; -/** Data rows for array [`functions`](#functions) - */ -export interface functionsRow { +/** Data for array rows [`functions`](#functions) */ +export interface functionsData { /** Entry identifier. */ key: Json.Key<'functions'>; /** Name */ @@ -129,39 +150,34 @@ export interface functionsRow { signature: string; } - -/** Data fetcher for array [`functions`](#functions) - */ -export const functionsFetch: Server.GetRequest = { +/** Data fetcher for array [`functions`](#functions) */ +export const fetchFunctions: Server.GetRequest = { kind: Server.RqKind.GET, - name: 'kernel.ast.functionsFetch', + name: 'kernel.ast.fetchFunctions', }; - -/** Force full reload for array [`functions`](#functions) - */ -export const functionsReload: Server.GetRequest = { +/** Force full reload for array [`functions`](#functions) */ +export const reloadFunctions: Server.GetRequest = { kind: Server.RqKind.GET, - name: 'kernel.ast.functionsReload', + name: 'kernel.ast.reloadFunctions', }; - /** Get textual information about a marker */ export const getInfo: Server.GetRequest = { kind: Server.RqKind.GET, name: 'kernel.ast.getInfo', }; - /** Get the currently analyzed source file names */ export const getFiles: Server.GetRequest = { kind: Server.RqKind.GET, name: 'kernel.ast.getFiles', }; - /** Set the source file names to analyze. */ export const setFiles: Server.SetRequest = { kind: Server.RqKind.SET, name: 'kernel.ast.setFiles', }; + +/* ------------------------------------- */ diff --git a/ivette/api/kernel/data.ts b/ivette/api/kernel/data.ts index 4e8e6ac0c721c38f91904fa4b9b39b753a969eb5..9ea5ff796429f00cf74c134f0475b109e9f58d57 100644 --- a/ivette/api/kernel/data.ts +++ b/ivette/api/kernel/data.ts @@ -1,6 +1,7 @@ /* --- Generated Frama-C Server API --- */ -/** Informations +/** + Informations @packageDocumentation @module frama-c/kernel/data */ @@ -12,10 +13,45 @@ import * as Server from 'frama-c/server'; /** Markdown (inlined) text. */ export type markdown = string; +/** Safe decoder for `markdown` */ +export const jMarkdownSafe: Json.Safe<markdown> = + Json.jFail(Json.jString,'String expected'); + +/** Loose decoder for `markdown` */ +export const jMarkdown: Json.Loose<markdown> = Json.jString; + +/** Natural order for `markdown` */ /** 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[]; +/** Safe decoder for `text` */ +export const jTextSafe: Json.Safe<text> = Json.jFail(jText,'Text expected'); + +/** Loose decoder for `text` */ +export const jText: Json.Loose<text> = + Json.jUnion<null | string | text[]>( + Json.jNull, + Json.jString, + Json.jList(jText), + ); + +/** Natural order for `text` */ /** Enum Tag Description */ export type tag = { name: string, label: markdown, descr: markdown }; + +/** Safe decoder for `tag` */ +export const jTagSafe: Json.Safe<tag> = + Json.jObject({ + name: Json.jFail(Json.jString,'String expected'), + label: jMarkdownSafe, + descr: jMarkdownSafe, + }); + +/** Loose decoder for `tag` */ +export const jTag: Json.Loose<tag> = Json.jTry(jTagSafe); + +/** Natural order for `tag` */ + +/* ------------------------------------- */ diff --git a/ivette/api/kernel/project.ts b/ivette/api/kernel/project.ts index e26fc66c7ee86f0fcd8b7d22ceeae2fe5e3fc73c..41a0996a639004c1ee68884fd3bd0a8b7f280e69 100644 --- a/ivette/api/kernel/project.ts +++ b/ivette/api/kernel/project.ts @@ -1,6 +1,7 @@ /* --- Generated Frama-C Server API --- */ -/** Project Management +/** + Project Management @packageDocumentation @module frama-c/kernel/project */ @@ -13,11 +14,37 @@ import * as Server from 'frama-c/server'; export type projectInfo = { id: Json.Key<'project'>, name: string, current: boolean }; +/** Safe decoder for `projectInfo` */ +export const jProjectInfoSafe: Json.Safe<projectInfo> = + Json.jObject({ + id: Json.jFail(Json.jKey('project'),'#project expected'), + name: Json.jFail(Json.jString,'String expected'), + current: Json.jFail(Json.jBoolean,'Boolean expected'), + }); + +/** Loose decoder for `projectInfo` */ +export const jProjectInfo: Json.Loose<projectInfo> = + Json.jTry(jProjectInfoSafe); + +/** Natural order for `projectInfo` */ /** Request to be executed on the specified project. */ export type projectRequest = { project: Json.Key<'project'>, request: string, data: Json.json }; +/** Safe decoder for `projectRequest` */ +export const jProjectRequestSafe: Json.Safe<projectRequest> = + Json.jObject({ + project: Json.jFail(Json.jKey('project'),'#project expected'), + request: Json.jFail(Json.jString,'String expected'), + data: Json.jAny, + }); + +/** Loose decoder for `projectRequest` */ +export const jProjectRequest: Json.Loose<projectRequest> = + Json.jTry(jProjectRequestSafe); + +/** Natural order for `projectRequest` */ /** Returns the current project */ export const getCurrent: Server.GetRequest = { @@ -25,44 +52,40 @@ export const getCurrent: Server.GetRequest = { name: 'kernel.project.getCurrent', }; - /** Switches the current project */ export const setCurrent: Server.SetRequest = { kind: Server.RqKind.SET, name: 'kernel.project.setCurrent', }; - /** Returns the list of all projects */ export const getList: Server.GetRequest = { kind: Server.RqKind.GET, name: 'kernel.project.getList', }; - /** Execute a GET request within the given project */ export const getOn: Server.GetRequest = { kind: Server.RqKind.GET, name: 'kernel.project.getOn', }; - /** Execute a SET request within the given project */ export const setOn: Server.SetRequest = { kind: Server.RqKind.SET, name: 'kernel.project.setOn', }; - /** Execute an EXEC request within the given project */ export const execOn: Server.ExecRequest = { kind: Server.RqKind.EXEC, name: 'kernel.project.execOn', }; - /** Create a new project */ export const create: Server.SetRequest = { kind: Server.RqKind.SET, name: 'kernel.project.create', }; + +/* ------------------------------------- */ diff --git a/ivette/api/kernel/properties.ts b/ivette/api/kernel/properties.ts index 807ed404695a4209d413526bf4b6cb78327b91b3..05d00856eda9c55faf7a029ff863448cc64de3d2 100644 --- a/ivette/api/kernel/properties.ts +++ b/ivette/api/kernel/properties.ts @@ -1,16 +1,17 @@ /* --- Generated Frama-C Server API --- */ -/** Property Services +/** + Property Services @packageDocumentation @module frama-c/kernel/properties */ import * as Json from 'dome/data/json'; import * as Server from 'frama-c/server'; + import { tag } from 'api/kernel/data'; import { source } from 'api/kernel/services'; - /** Property Kinds */ export enum propKind { /** Contract behavior */ @@ -83,14 +84,21 @@ export enum propKind { prop:<prop> = 'prop:<prop>'; } +/** Safe decoder for `propKind` */ +export const jPropKindSafe: Json.Safe<propKind> = + Json.jFail(Json.jEnum(propKind),'kernel.properties.propKind expected'); + +/** Loose decoder for `propKind` */ +export const jPropKind: Json.Loose<propKind> = Json.jEnum(propKind); -/** Returns all registered tags for the above type. */ +/** Natural order for `propKind` */ + +/** Registered tags for the above type. */ export const propKindTags: Server.GetRequest = { kind: Server.RqKind.GET, name: 'kernel.properties.propKindTags', }; - /** Property Status (consolidated) */ export enum propStatus { /** Unknown status */ @@ -117,14 +125,21 @@ export enum propStatus { unknown_but_dead = 'unknown_but_dead'; } +/** Safe decoder for `propStatus` */ +export const jPropStatusSafe: Json.Safe<propStatus> = + Json.jFail(Json.jEnum(propStatus),'kernel.properties.propStatus expected'); -/** Returns all registered tags for the above type. */ +/** Loose decoder for `propStatus` */ +export const jPropStatus: Json.Loose<propStatus> = Json.jEnum(propStatus); + +/** Natural order for `propStatus` */ + +/** Registered tags for the above type. */ export const propStatusTags: Server.GetRequest = { kind: Server.RqKind.GET, name: 'kernel.properties.propStatusTags', }; - /** Alarm Kinds */ export enum alarms { /** Integer division by zero */ @@ -165,27 +180,35 @@ export enum alarms { bool_value = 'bool_value'; } +/** Safe decoder for `alarms` */ +export const jAlarmsSafe: Json.Safe<alarms> = + Json.jFail(Json.jEnum(alarms),'kernel.properties.alarms expected'); + +/** Loose decoder for `alarms` */ +export const jAlarms: Json.Loose<alarms> = Json.jEnum(alarms); -/** Returns all registered tags for the above type. */ +/** Natural order for `alarms` */ + +/** Registered tags for the above type. */ export const alarmsTags: Server.GetRequest = { kind: Server.RqKind.GET, name: 'kernel.properties.alarmsTags', }; - /** Status of Registered Properties */ - - -/** Signal for array [`status`](#status) - */ -export const statusSig: Server.Signal = { - name: 'kernel.properties.statusSig', +export const status: State.Array<'status',statusData> = { + signal: signalStatus, + fetch: fetchStatus, + reload: reloadStatus, }; +/** Signal for array [`status`](#status) */ +export const signalStatus: Server.Signal = { + name: 'kernel.properties.signalStatus', +}; -/** Data rows for array [`status`](#status) - */ -export interface statusRow { +/** Data for array rows [`status`](#status) */ +export interface statusData { /** Entry identifier. */ key: Json.Key<'status'>; /** Full description */ @@ -210,18 +233,16 @@ export interface statusRow { predicate?: string; } - -/** Data fetcher for array [`status`](#status) - */ -export const statusFetch: Server.GetRequest = { +/** Data fetcher for array [`status`](#status) */ +export const fetchStatus: Server.GetRequest = { kind: Server.RqKind.GET, - name: 'kernel.properties.statusFetch', + name: 'kernel.properties.fetchStatus', }; - -/** Force full reload for array [`status`](#status) - */ -export const statusReload: Server.GetRequest = { +/** Force full reload for array [`status`](#status) */ +export const reloadStatus: Server.GetRequest = { kind: Server.RqKind.GET, - name: 'kernel.properties.statusReload', + name: 'kernel.properties.reloadStatus', }; + +/* ------------------------------------- */ diff --git a/ivette/api/kernel/services.ts b/ivette/api/kernel/services.ts index d14b2be23074dbb022ab3f73f383efe0c83ec0bb..db7c4f085dfe468c2f6bff849cc8f1c67741e93f 100644 --- a/ivette/api/kernel/services.ts +++ b/ivette/api/kernel/services.ts @@ -1,14 +1,15 @@ /* --- Generated Frama-C Server API --- */ -/** Kernel Services +/** + Kernel Services @packageDocumentation @module frama-c/kernel/services */ import * as Json from 'dome/data/json'; import * as Server from 'frama-c/server'; -import { tag } from 'api/kernel/data'; +import { tag } from 'api/kernel/data'; /** Frama-C Kernel configuration */ export const getConfig: Server.GetRequest = { @@ -16,18 +17,29 @@ export const getConfig: Server.GetRequest = { name: 'kernel.services.getConfig', }; - /** Load a save file. Returns an error, if not successfull. */ export const load: Server.SetRequest = { kind: Server.RqKind.SET, name: 'kernel.services.load', }; - /** Source file positions. */ export type source = { dir: string, base: string, file: string, line: number }; +/** Safe decoder for `source` */ +export const jSourceSafe: Json.Safe<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'), + }); + +/** Loose decoder for `source` */ +export const jSource: Json.Loose<source> = Json.jTry(jSourceSafe); + +/** Natural order for `source` */ /** Log messages categories. */ export enum logkind { @@ -45,14 +57,21 @@ export enum logkind { DEBUG = 'DEBUG'; } +/** Safe decoder for `logkind` */ +export const jLogkindSafe: Json.Safe<logkind> = + Json.jFail(Json.jEnum(logkind),'kernel.services.logkind expected'); + +/** Loose decoder for `logkind` */ +export const jLogkind: Json.Loose<logkind> = Json.jEnum(logkind); -/** Returns all registered tags for the above type. */ +/** Natural order for `logkind` */ + +/** Registered tags for the above type. */ export const logkindTags: Server.GetRequest = { kind: Server.RqKind.GET, name: 'kernel.services.logkindTags', }; - /** Message event record. */ export interface log { /** Message kind */ @@ -67,6 +86,20 @@ export interface log { source?: source; } +/** Safe decoder for `log` */ +export const jLogSafe: Json.Safe<log> = + Json.jObject({ + kind: Json.jFail(Json.jEnum(logkind),'kernel.services.logkind expected'), + plugin: Json.jFail(Json.jString,'String expected'), + message: Json.jFail(Json.jString,'String expected'), + category: Json.jString, + source: jSource, + }); + +/** Loose decoder for `log` */ +export const jLog: Json.Loose<log> = Json.jTry(jLogSafe); + +/** Natural order for `log` */ /** Turn logs monitoring on/off */ export const setLogs: Server.SetRequest = { @@ -74,9 +107,10 @@ export const setLogs: Server.SetRequest = { name: 'kernel.services.setLogs', }; - /** Flush the last emitted logs since last call (max 100) */ export const getLogs: Server.GetRequest = { kind: Server.RqKind.GET, name: 'kernel.services.getLogs', }; + +/* ------------------------------------- */ diff --git a/ivette/api/server_tsc.ml b/ivette/api/server_tsc.ml index 9028a35c14ae21e3bbfb346cb7ad8b75d326cec7..a5139d848c6c14899a316a138c8aace0cc1bc415 100644 --- a/ivette/api/server_tsc.ml +++ b/ivette/api/server_tsc.ml @@ -49,6 +49,10 @@ let name_of_kind = function | `SET -> "SET" | `EXEC -> "EXEC" +let makeDescr ?(indent="") fmt descr = + if descr <> [] then + Format.fprintf fmt "%s/** @[<hov 0>%a@] */@." indent pp_descr descr + (* -------------------------------------------------------------------------- *) (* --- Jtype Generator --- *) (* -------------------------------------------------------------------------- *) @@ -61,15 +65,15 @@ let makeJtype ~self ~names = | exception Not_found -> Self.abort "Undefined '%a'" pp_ident id in let rec pp fmt = function | Jany -> Format.pp_print_string fmt "Json.json" - | Jself -> Format.pp_print_string fmt self + | Jself -> Format.pp_print_string fmt self.name | Jnull -> Format.pp_print_string fmt "null" | Jnumber -> Format.pp_print_string fmt "number" | Jboolean -> Format.pp_print_string fmt "boolean" - | Jstring -> Format.pp_print_string fmt "string" - | Jtag tag -> Format.fprintf fmt "'%s'" tag + | Jstring | Jalpha -> Format.pp_print_string fmt "string" | Jkey kd -> Format.fprintf fmt "Json.Key<'%s'>" kd | Jindex kd -> Format.fprintf fmt "Json.Index<'%s'>" kd - | Jdata id -> pp_ident fmt id + | Jdict(kd,js) -> Format.fprintf fmt "Json.Dict<'%s',%a>" kd pp js + | Jdata id | Jenum id -> pp_ident fmt id | Joption js -> Format.fprintf fmt "%a |@ undefined" pp js | Jtuple js -> Pretty_utils.pp_list ~pre:"@[<hov 2>[ " ~sep:",@ " ~suf:"@ ]@]" pp fmt js @@ -77,31 +81,134 @@ 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 -> Format.fprintf fmt "%a[]" protect js - | Jassoc (kd,js) -> Format.fprintf fmt "Json.Dict<'%s',%a>" kd pp js + | Jarray js | Jlist 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 and field fmt (fd,js) = Format.fprintf fmt "@[<hov 4>%s:@ %a@]" fd pp js in pp +(* -------------------------------------------------------------------------- *) +(* --- Jtype Decoder --- *) +(* -------------------------------------------------------------------------- *) + +let jprim fmt name = Format.fprintf fmt "Json.%s" name +let jkey fmt kd = Format.fprintf fmt "Json.jKey('%s')" kd +let jindex fmt kd = Format.fprintf fmt "Json.jIndex('%s')" kd + +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 + else + Format.fprintf fmt "@[<hov 2>Json.jTry(@,%a)@]" pp d + +let jenum names fmt id = Format.fprintf fmt "Json.jEnum(%a)" (jcall names) id + +let junion ~jtype ~makeLoose 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 ; + Format.fprintf fmt "@]@,)@]" ; + end + +let jrecord ~makeSafe 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 "@]@,})@]" ; + end + +let jtuple ~makeSafe fmt jts = + begin + let name = match List.length jts with + | 2 -> "jPair" + | 3 -> "jTriple" + | 4 -> "jTuple4" + | 5 -> "jTuple5" + | n -> Self.fatal "No jTuple%d defined" n + in + Format.fprintf fmt "@[<hv 0>@[<hv 2>Json.%s(" name ; + List.iter + (fun js -> Format.fprintf fmt "@ @[<hov 2>%a@]," makeSafe js) jts ; + Format.fprintf fmt "@]@,)@]" ; + end + +let rec makeDecoder ~safe ~self ~names fmt js = + let open Pkg in + let makeSafe = makeDecoder ~self ~names ~safe:true in + let makeLoose = makeDecoder ~self ~names ~safe:false 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" + | Jkey kd -> jsafe ~safe ("#" ^ kd) jkey fmt kd + | Jindex kd -> jsafe ~safe ("#0" ^ 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 self) + | Joption js -> makeLoose fmt js + | Jdict(kd,js) -> + Format.fprintf fmt "@[<hov 2>Json.jDict('%s',@,%a)@]" kd makeLoose js + | Jlist js -> + Format.fprintf fmt "@[<hov 2>Json.jList(%a)@]" makeLoose 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 + | Junion jts -> + let jtype = makeJtype ~self ~names in + jsafe ~safe "Union" (junion ~jtype ~makeLoose) fmt jts + | Jrecord jfs -> jtry ~safe (jrecord ~makeSafe) fmt jfs + | Jtuple jts -> jtry ~safe (jtuple ~makeSafe) fmt jts + +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) + | Jrecord _ | Jtuple _ | Jarray _ when not safe -> + Format.fprintf fmt "Json.jTry(%a)" + (jcall names) (Pkg.Derived.safe self) + | Junion _ 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 + (* -------------------------------------------------------------------------- *) (* --- Declaration Generator --- *) (* -------------------------------------------------------------------------- *) let makeDeclaration fmt names d = let open Pkg in - Format.fprintf fmt "@\n@\n/** %a */@\n" pp_descr d.d_descr ; - let self = d.d_ident.name in + Format.pp_print_newline fmt () ; + makeDescr fmt d.d_descr ; + let self = d.d_ident in let jtype = makeJtype ~self ~names in match d.d_kind with | D_type js -> - Format.fprintf fmt "@[<hv 2>export type %s =@ %a;@]@\n" self jtype js ; + Format.fprintf fmt "@[<hv 2>export type %s =@ %a;@]@\n" self.name jtype js ; | D_record fjs -> - Format.fprintf fmt "export interface %s {@\n" self ; + Format.fprintf fmt "export interface %s {@\n" self.name ; List.iter (fun { fd_name = fd ; fd_type = js ; fd_descr = doc } -> - if doc<>[] then Format.fprintf fmt " /** %a */@\n" pp_descr doc ; + makeDescr ~indent:" " fmt doc ; match js with | Joption js -> Format.fprintf fmt " @[<hov 2>%s?: %a;@]@\n" fd jtype js @@ -110,25 +217,63 @@ let makeDeclaration fmt names d = ) fjs ; Format.fprintf fmt "}@\n" ; | D_enum tgs -> - Format.fprintf fmt "export enum %s {@\n" self ; + Format.fprintf fmt "export enum %s {@\n" self.name ; List.iter (fun { tg_name = tag ; tg_descr = doc } -> - if doc<>[] then Format.fprintf fmt " /** %a */@\n" pp_descr doc ; + makeDescr ~indent:" " fmt doc ; Format.fprintf fmt " %s = '%s';@\n" tag tag ; ) tgs ; Format.fprintf fmt "}@\n" ; | D_request rq -> let kind = name_of_kind rq.rq_kind in let prefix = String.capitalize_ascii (String.lowercase_ascii kind) in - Format.fprintf fmt "export const %s: Server.%sRequest = {@\n" self prefix ; + Format.fprintf fmt "export const %s: Server.%sRequest = {@\n" + self.name prefix ; Format.fprintf fmt " kind: Server.RqKind.%s,@\n" kind ; Format.fprintf fmt " name: '%s',@\n" (Pkg.name_of_ident d.d_ident) ; Format.fprintf fmt "};@\n" ; | D_signal -> - Format.fprintf fmt "export const %s: Server.Signal = {@\n" self ; + Format.fprintf fmt "export const %s: Server.Signal = {@\n" self.name ; Format.fprintf fmt " name: '%s',@\n" (Pkg.name_of_ident d.d_ident) ; Format.fprintf fmt "};@\n" ; - | _ -> () + | D_value js -> + Format.fprintf fmt "export const %s: State.Value<%a> = {@\n" + self.name jtype js ; + Format.fprintf fmt " signal: %a,@\n" + (jcall names) (Pkg.Derived.signal self) ; + Format.fprintf fmt " getter: %a,@\n" + (jcall names) (Pkg.Derived.getter self) ; + Format.fprintf fmt "};@\n" ; + | D_state js -> + Format.fprintf fmt "export const %s: State.State<%a> = {@\n" + self.name jtype js ; + Format.fprintf fmt " signal: %a,@\n" + (jcall names) (Pkg.Derived.signal self) ; + Format.fprintf fmt " getter: %a,@\n" + (jcall names) (Pkg.Derived.getter self) ; + Format.fprintf fmt " setter: %a,@\n" + (jcall names) (Pkg.Derived.setter self) ; + Format.fprintf fmt "};@\n" ; + | D_array kd -> + let data = Pkg.Derived.data self in + Format.fprintf fmt "export const %s: State.Array<'%s',%a> = {@\n" + self.name kd (jcall names) data ; + Format.fprintf fmt " signal: %a,@\n" + (jcall names) (Pkg.Derived.signal self) ; + Format.fprintf fmt " fetch: %a,@\n" + (jcall names) (Pkg.Derived.fetch self) ; + Format.fprintf fmt " reload: %a,@\n" + (jcall names) (Pkg.Derived.reload self) ; + Format.fprintf fmt "};@\n" ; + | D_safe(id,js) -> + Format.fprintf fmt "@[<hov 2>export const %s: Json.Safe<%a> =@ %a;@]\n" + self.name (jcall names) id + (makeRootDecoder ~safe:true ~self:id ~names) js ; + | D_loose(id,js) -> + Format.fprintf fmt "@[<hov 2>export const %s: Json.Loose<%a> =@ %a;@]\n" + self.name (jcall names) id + (makeRootDecoder ~safe:false ~self:id ~names) js ; + | D_order _ -> () (* -------------------------------------------------------------------------- *) (* --- Package Generator --- *) @@ -138,15 +283,16 @@ let makePackage pkg name fmt = begin let open Pkg in Format.fprintf fmt "/* --- Generated Frama-C Server API --- */@\n@\n" ; - Format.fprintf fmt "/** %s@\n" pkg.p_title ; + Format.fprintf fmt "/**@\n %s@\n" pkg.p_title ; if pkg.p_descr <> [] then - Format.fprintf fmt "@\n@\n%a@\n" pp_descr pkg.p_descr ; + Format.fprintf fmt "@\n @[<hov 0>%a@]@\n@\n" pp_descr pkg.p_descr ; Format.fprintf fmt " @@packageDocumentation@\n" ; Format.fprintf fmt " @@module frama-c/%s@\n" name ; - Format.fprintf fmt "*/@\n@\n" ; + Format.fprintf fmt "*/@\n@." ; let names = Pkg.resolve ~keywords pkg in Format.fprintf fmt "import * as Json from 'dome/data/json';@\n" ; Format.fprintf fmt "import * as Server from 'frama-c/server';@\n" ; + Format.pp_print_newline fmt () ; Pkg.IdMap.iter (fun id name -> if id.plugin <> pkg.p_plugin || @@ -160,7 +306,9 @@ let makePackage pkg name fmt = Format.fprintf fmt "import { %s: %s } from 'api/%s';@\n" id.name name pkg ) names ; - List.iter (makeDeclaration fmt names) pkg.p_content + List.iter (makeDeclaration fmt names) pkg.p_content ; + Format.pp_print_newline fmt () ; + Format.fprintf fmt "/* ------------------------------------- */@." ; end (* -------------------------------------------------------------------------- *) diff --git a/src/plugins/server/data.ml b/src/plugins/server/data.ml index e6cc295d6d0c21e861c1baf17ffdedd13449cd3e..75833d9b4613c2d03ce89f8705d4de956d0e781c 100644 --- a/src/plugins/server/data.ml +++ b/src/plugins/server/data.ml @@ -57,6 +57,28 @@ let failure_from_type_error msg json = let package = Package.package ~name:"data" ~title:"Informations" () +(* -------------------------------------------------------------------------- *) +(* --- Declared Type --- *) +(* -------------------------------------------------------------------------- *) + +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.order id).name + ~descr:(Md.plain "Natural order for" @ Md.code id.name) + (D_order(id,jtype)) ; + end + +let declare ~package ~name ?descr jtype = + let id = declare_id ~package ~name ?descr (D_type jtype) in + derived ~package ~id jtype ; Jdata id + (* -------------------------------------------------------------------------- *) (* --- Option --- *) (* -------------------------------------------------------------------------- *) @@ -195,12 +217,16 @@ struct let to_json s = `String s end +(* -------------------------------------------------------------------------- *) +(* --- Text Datatypes --- *) +(* -------------------------------------------------------------------------- *) + module Jmarkdown : S with type t = Markdown.text = struct type t = Markdown.text let jtype = let descr = Markdown.plain "Markdown (inlined) text." in - datatype ~package ~name:"markdown" ~descr Jstring + declare ~package ~name:"markdown" ~descr Jstring let of_json js = Markdown.plain (Ju.to_string js) let to_json txt = `String (Pretty_utils.to_string Markdown.pp_text txt) end @@ -213,8 +239,8 @@ 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; Jarray Jself ] in - datatype ~package ~name:"text" ~descr jdef + let jdef = Junion [ Jnull; Jstring; Jlist Jself ] in + declare ~package ~name:"text" ~descr jdef end (* -------------------------------------------------------------------------- *) @@ -350,8 +376,11 @@ struct type nonrec r = r type t = r record let jtype = - let record = D_record (List.rev s.fields) in - Jdata (Package.declare_id ~package ~name ~descr record) + let fields = List.rev s.fields in + let id = Package.declare_id ~package ~name ~descr (D_record fields) in + let field fd = fd.fd_name, fd.fd_type in + derived ~package ~id (Jrecord (List.map field fields)) ; + Jdata id let default = s.default let has fd r = fd.member r let get fd r = fd.getter r @@ -380,8 +409,7 @@ module Tag = struct type t = Package.tagInfo - let jtype = - datatype ~package ~name:"tag" + let jtype = declare ~package ~name:"tag" ~descr:(Markdown.plain "Enum Tag Description") (Jrecord [ "name",Jstring ; @@ -520,7 +548,9 @@ struct type t = a let jtype = let enums = D_enum (List.rev d.tags) in - Jdata (Package.declare_id ~package ~name ~descr enums) + let id = Package.declare_id ~package ~name ~descr enums in + let js = Jenum id in + derived ~package ~id js ; js let of_json = of_json name d.values let to_json = to_json name d.lookup d.vindex end in diff --git a/src/plugins/server/data.mli b/src/plugins/server/data.mli index 6ee41b06e217f64cf381e0ca8af834f7bf3fb31b..6134493c968e528edd6e99098642c8a5e037cf72 100644 --- a/src/plugins/server/data.mli +++ b/src/plugins/server/data.mli @@ -115,6 +115,23 @@ val jalist : 'a data -> 'a list data val jarray : 'a data -> 'a array data val joption : 'a data -> 'a option data +(** + Declare the derived names for the provided type. + Shall not be used directely. +*) +val derived : package:package -> id:ident -> jtype -> unit + +(** + Declare a new type and returns its alias. + Same as [Jdata (declare_id ~package ~name (D_type js))]. + Automatically declare the derived names. +*) +val declare : + package:package -> + name:string -> + ?descr:Markdown.text -> + jtype -> jtype + (* -------------------------------------------------------------------------- *) (** {2 Records} *) (* -------------------------------------------------------------------------- *) diff --git a/src/plugins/server/kernel_ast.ml b/src/plugins/server/kernel_ast.ml index 6bbd4d7c472faf4cd96a0d428b266efe44238f6a..a278440a524f50a1d051e66b5ccf01616e06a245 100644 --- a/src/plugins/server/kernel_ast.ml +++ b/src/plugins/server/kernel_ast.ml @@ -185,7 +185,7 @@ struct let jglobal = jmarker "global" let jproperty = jmarker "property" - let jtype = Pkg.datatype ~package ~name:"marker" + let jtype = Data.declare ~package ~name:"marker" ~descr:(Md.plain "Localizable AST markers") Pkg.(Junion (List.rev !markers)) diff --git a/src/plugins/server/kernel_main.ml b/src/plugins/server/kernel_main.ml index 1c7166aab805aea19848f336c516bd206906ed74..a09524ecd4b6e8440541c5a83fac0bdd20f7fc28 100644 --- a/src/plugins/server/kernel_main.ml +++ b/src/plugins/server/kernel_main.ml @@ -79,7 +79,7 @@ module LogSource = struct type t = Filepath.position - let jtype = Pkg.datatype ~package ~name:"source" + let jtype = Data.declare ~package ~name:"source" ~descr:(Md.plain "Source file positions.") (Jrecord [ "dir", Jstring; diff --git a/src/plugins/server/kernel_project.ml b/src/plugins/server/kernel_project.ml index 7d96485713a9ef3a1a0ecce0bcad682c30db541c..80a7b106b5187e2fec1fe6dadb7d9ea5add05cc7 100644 --- a/src/plugins/server/kernel_project.ml +++ b/src/plugins/server/kernel_project.ml @@ -37,7 +37,7 @@ module ProjectId = (val jkey ~kind:"project") module ProjectInfo = struct type t = Project.t - let jtype = Pkg.datatype ~package + let jtype = Data.declare ~package ~name:"projectInfo" ~descr:(Md.plain "Project informations") Pkg.(Jrecord [ @@ -68,7 +68,7 @@ struct type t = Project.t * string * json - let jtype = Pkg.datatype ~package ~name:"projectRequest" + let jtype = Data.declare ~package ~name:"projectRequest" ~descr:(Md.plain "Request to be executed on the specified project.") (Jrecord [ "project",ProjectId.jtype; diff --git a/src/plugins/server/package.ml b/src/plugins/server/package.ml index b5fb7e83f50194f5635bebe593c08e11e439bb80..29f47cd79b6abe044e1e948567c23eda4a665a56 100644 --- a/src/plugins/server/package.ml +++ b/src/plugins/server/package.ml @@ -166,17 +166,17 @@ type jtype = | Jnumber | Jstring | Jalpha (* string primarily compared without case *) - | Jtag of string | Jkey of string (* kind of a string used for indexing *) | Jindex of string (* kind of an integer used for indexing *) | Joption of jtype - | Jassoc of string * jtype (* kind of keys *) + | Jdict of string * jtype (* kind of keys *) | Jlist of jtype (* order does not matter *) | Jarray of jtype (* order matters *) | Jtuple of jtype list | Junion of jtype list | Jrecord of (string * jtype) list | Jdata of ident + | Jenum of ident (* data that is an enum *) | Jself (* for (simply) recursive types *) (* -------------------------------------------------------------------------- *) @@ -214,6 +214,9 @@ type declKindInfo = | D_value of jtype | D_state of jtype | D_array of string (* key kind *) + | D_safe of ident * jtype (* safe decoder *) + | D_loose of ident * jtype (* loose decoder *) + | D_order of ident * jtype (* natural ordering *) type declInfo = { d_ident : ident; @@ -253,11 +256,11 @@ let pp_pkgname fmt { p_plugin ; p_package } = let rec visit_jtype fn = function | Jany | Jself | Jnull | Jboolean | Jnumber - | Jstring | Jalpha | Jkey _ | Jindex _ | Jtag _ -> () - | Joption js | Jassoc(_,js) | Jarray js | Jlist js -> visit_jtype fn js + | Jstring | Jalpha | Jkey _ | Jindex _ -> () + | Joption js | Jdict(_,js) | Jarray js | Jlist 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 -> fn id + | Jdata id | Jenum id -> fn id let visit_field f { fd_type } = visit_jtype f fd_type @@ -271,6 +274,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_record fds -> List.iter (visit_field f) fds | D_request rq -> visit_request f rq @@ -303,12 +307,16 @@ let derived ?prefix ?suffix id = module Derived = struct - let signal id = derived ~prefix:"sig" id + let signal id = derived ~prefix:"signal" id let getter id = derived ~prefix:"get" id let setter id = derived ~prefix:"set" id let data id = derived ~suffix:"Data" id 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 end (* -------------------------------------------------------------------------- *) @@ -399,9 +407,6 @@ let update ~package:pkg ~name decl = else curr ) pkg.revDecl -let datatype ~package ~name ?descr jtype = - Jdata (declare_id ~package ~name ?descr (D_type jtype)) - let iter f = List.iter f @@ match !collection with @@ -434,16 +439,15 @@ let rec md_jtype pp = function | Jnumber -> Md.emph "number" | Jboolean -> Md.emph "boolean" | Jstring | Jalpha -> Md.emph "string" - | Jtag tag -> escaped tag | Jkey kd -> key kd | Jindex kd -> index kd - | Jdata id -> pp.ident id + | Jdata id | Jenum id -> pp.ident id | 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 "[]" | Jrecord fjs -> Md.code "{" @ fields pp fjs @ Md.code "}" - | Jassoc (id,js) -> + | Jdict (id,js) -> Md.code "{[" @ key id @ Md.code "]:" @ md_jtype pp js @ Md.code "}" and md_jlist pp sep js = diff --git a/src/plugins/server/package.mli b/src/plugins/server/package.mli index 0e3605c50f18465be741f4468dc63e8d1807e11e..0e639a0ee9e584fb6738a1fdc0e1ee8f1da13d85 100644 --- a/src/plugins/server/package.mli +++ b/src/plugins/server/package.mli @@ -34,17 +34,17 @@ type jtype = | Jnumber | Jstring | Jalpha (** string primarily compared without case *) - | Jtag of string | Jkey of string (** kind of a string used for indexing *) | Jindex of string (** kind of an integer used for indexing *) | Joption of jtype - | Jassoc of string * jtype (** kind of keys *) + | Jdict of string * jtype (** kind of keys *) | Jlist of jtype (** order does not matter *) | Jarray of jtype (** order matters *) | Jtuple of jtype list | Junion of jtype list | Jrecord of (string * jtype) list | Jdata of ident + | Jenum of ident (** data that is an enum *) | Jself (** for (simply) recursive types *) type fieldInfo = { @@ -78,6 +78,9 @@ type declKindInfo = | D_value of jtype | D_state of jtype | D_array of string + | D_safe of ident * jtype (* safe decoder *) + | D_loose of ident * jtype (* loose decoder *) + | D_order of ident * jtype (* natural ordering *) type declInfo = { d_ident : ident; @@ -103,7 +106,6 @@ val pp_pkgname : Format.formatter -> packageInfo -> unit val pp_ident : Format.formatter -> ident -> unit val pp_jtype : Format.formatter -> jtype -> unit - (* -------------------------------------------------------------------------- *) (* --- Derived Names --- *) (* -------------------------------------------------------------------------- *) @@ -118,6 +120,10 @@ 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 end (* -------------------------------------------------------------------------- *) @@ -181,16 +187,6 @@ val declare_id : declKindInfo -> ident -(** - Declare a new type and returns its alias. - Same as [Jdata (declare_id ~package ~name (D_type js))]` -*) -val datatype : - package:package -> - name:string -> - ?descr:Markdown.text -> - jtype -> jtype - (** Replace the declaration for the given name in the package. *) diff --git a/src/plugins/server/server_doc.ml b/src/plugins/server/server_doc.ml index fa71c4a6fae13631348b74f95fe5200afe0002c9..522cc6584cfffdbadf3508ce01515780ef9ab1d5 100644 --- a/src/plugins/server/server_doc.ml +++ b/src/plugins/server/server_doc.ml @@ -134,6 +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 let pp_for ?decl names = let self = @@ -158,6 +159,7 @@ let md_named ~kind pp = function let descr_of_decl names decl = match decl.d_kind with + | D_safe _ | D_loose _ | D_order _ -> assert false | D_signal -> [] | D_state _ -> [] (* TBC *) | D_value _ -> [] (* TBC *) @@ -181,16 +183,19 @@ let descr_of_decl names decl = md_named ~kind:"output" pp rq.rq_output let declaration page names decl = - let name = decl.d_ident.name in - let fullname = name_of_ident decl.d_ident in - let kind = kind_of_decl decl.d_kind in - (* let title = Printf.sprintf "`%s` %s" kind fullname in *) - let title = Printf.sprintf "%s (`%s`)" fullname kind in - let index = [ title ] in - let contents = Markdown.par decl.d_descr in - let generated () = descr_of_decl names decl in - let _href = publish ~page ~name ~title ~index ~contents ~generated () in - () + match decl.d_kind with + | D_safe _ | D_loose _ | D_order _ -> () + | _ -> + let name = decl.d_ident.name in + let fullname = name_of_ident decl.d_ident in + let kind = kind_of_decl decl.d_kind in + (* let title = Printf.sprintf "`%s` %s" kind fullname in *) + let title = Printf.sprintf "%s (`%s`)" fullname kind in + let index = [ title ] in + let contents = Markdown.par decl.d_descr in + let generated () = descr_of_decl names decl in + let href = publish ~page ~name ~title ~index ~contents ~generated () in + ignore href let package pkg = begin