From a9cc087732e805d94f2df9f1f4bfdacafe3d819f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Loi=CC=88c=20Correnson?= <loic.correnson@cea.fr> Date: Wed, 24 Jun 2020 14:58:14 +0200 Subject: [PATCH] [ivette] request parameters --- ivette/api/dive.ts | 44 ++++++++---- ivette/api/kernel/ast.ts | 121 ++++++++++++++++++++++---------- ivette/api/kernel/project.ts | 50 ++++++++----- ivette/api/kernel/properties.ts | 52 ++++++++++---- ivette/api/kernel/services.ts | 41 ++++++++--- ivette/api/server_tsc.ml | 77 +++++++++++++------- src/plugins/server/package.ml | 60 +++++++++------- 7 files changed, 298 insertions(+), 147 deletions(-) diff --git a/ivette/api/dive.ts b/ivette/api/dive.ts index d00d62b0cba..de058d27793 100644 --- a/ivette/api/dive.ts +++ b/ivette/api/dive.ts @@ -32,45 +32,61 @@ export const jVariableName: Json.Loose<variableName> = /** Natural order for `variableName` */ /** Retrieve the whole graph */ -export const graph: Server.GetRequest = { +export const graph: Server.GetRequest<null,Json.json> = { kind: Server.RqKind.GET, - name: 'dive.graph', + name: 'dive.graph', + input: Json.jNull, + output: Json.jAny, }; /** Erase the graph and start over with an empty one */ -export const clear: Server.ExecRequest = { +export const clear: Server.ExecRequest<null,null> = { kind: Server.RqKind.EXEC, - name: 'dive.clear', + name: 'dive.clear', + input: Json.jNull, + output: Json.jNull, }; /** Add a variable to the graph */ -export const addVar: Server.ExecRequest = { +export const addVar: Server.ExecRequest<variableName,Json.json> = { kind: Server.RqKind.EXEC, - name: 'dive.addVar', + name: 'dive.addVar', + input: jVariableName, + output: Json.jAny, }; /** Add all alarms of the given function */ -export const addFunctionAlarms: Server.ExecRequest = { +export const addFunctionAlarms: Server.ExecRequest<Json.Key<'#fct'>,Json.json + > = { kind: Server.RqKind.EXEC, - name: 'dive.addFunctionAlarms', + name: 'dive.addFunctionAlarms', + input: Json.jKey('#fct'), + output: Json.jAny, }; /** Explore the graph starting from an existing vertex */ -export const explore: Server.ExecRequest = { +export const explore: Server.ExecRequest<Json.Index<'#dive-node'>,Json.json + > = { kind: Server.RqKind.EXEC, - name: 'dive.explore', + name: 'dive.explore', + input: Json.jIndex('#dive-node'), + output: Json.jAny, }; /** Show the dependencies of an existing vertex */ -export const show: Server.ExecRequest = { +export const show: Server.ExecRequest<Json.Index<'#dive-node'>,Json.json> = { kind: Server.RqKind.EXEC, - name: 'dive.show', + name: 'dive.show', + input: Json.jIndex('#dive-node'), + output: Json.jAny, }; /** Hide the dependencies of an existing vertex */ -export const hide: Server.ExecRequest = { +export const hide: Server.ExecRequest<Json.Index<'#dive-node'>,Json.json> = { kind: Server.RqKind.EXEC, - name: 'dive.hide', + name: 'dive.hide', + input: Json.jIndex('#dive-node'), + output: Json.jAny, }; /* ------------------------------------- */ diff --git a/ivette/api/kernel/ast.ts b/ivette/api/kernel/ast.ts index 52d70d3f034..b6016940b3d 100644 --- a/ivette/api/kernel/ast.ts +++ b/ivette/api/kernel/ast.ts @@ -9,13 +9,21 @@ import * as Json from 'dome/data/json'; import * as Server from 'frama-c/server'; +import { byTag } from 'api/kernel/data'; +import { byText } from 'api/kernel/data'; +import { jTag } from 'api/kernel/data'; +import { jTagSafe } from 'api/kernel/data'; +import { jText } from 'api/kernel/data'; +import { jTextSafe } from 'api/kernel/data'; import { tag } from 'api/kernel/data'; import { text } from 'api/kernel/data'; /** Ensures that AST is computed */ -export const compute: Server.ExecRequest = { +export const compute: Server.ExecRequest<null,null> = { kind: Server.RqKind.EXEC, - name: 'kernel.ast.compute', + name: 'kernel.ast.compute', + input: Json.jNull, + output: Json.jNull, }; /** Marker kind */ @@ -50,13 +58,15 @@ export const jMarkerKind: Json.Loose<markerKind> = Json.jEnum(markerKind); /** Natural order for `markerKind` */ /** Registered tags for the above type. */ -export const markerKindTags: Server.GetRequest = { +export const markerKindTags: Server.GetRequest<null,tag[]> = { kind: Server.RqKind.GET, - name: 'kernel.ast.markerKindTags', + name: 'kernel.ast.markerKindTags', + input: Json.jNull, + output: Json.jList(jTag), }; /** Markers data */ -export const markerData: State.Array<'markerData',markerDataData> = { +export const markerData: State.Array<'#markerData',markerDataData> = { signal: signalMarkerData, fetch: fetchMarkerData, reload: reloadMarkerData, @@ -70,7 +80,7 @@ export const signalMarkerData: Server.Signal = { /** Data for array rows [`markerData`](#markerdata) */ export interface markerDataData { /** Entry identifier. */ - key: Json.Key<'markerData'>; + key: Json.Key<'#markerData'>; /** Marker kind */ kind: markerKind; /** Marker short name */ @@ -80,21 +90,34 @@ export interface markerDataData { } /** Data fetcher for array [`markerData`](#markerdata) */ -export const fetchMarkerData: Server.GetRequest = { +export const fetchMarkerData: Server.GetRequest<number, + { pending: number, updated: markerDataData[], + removed: Json.Key<'#markerData'>[], reload: boolean }> = { kind: Server.RqKind.GET, - name: 'kernel.ast.fetchMarkerData', + name: 'kernel.ast.fetchMarkerData', + input: Json.jNumber, + output: Json.jTry( + Json.jObject({ + pending: Json.jFail(Json.jNumber,'Number expected'), + updated: Json.jList(jMarkerDataData), + removed: Json.jList(Json.jKey('#markerData')), + reload: Json.jFail(Json.jBoolean,'Boolean expected'), + })), }; /** Force full reload for array [`markerData`](#markerdata) */ -export const reloadMarkerData: Server.GetRequest = { +export const reloadMarkerData: Server.GetRequest<null,null> = { kind: Server.RqKind.GET, - name: 'kernel.ast.reloadMarkerData', + name: 'kernel.ast.reloadMarkerData', + input: Json.jNull, + output: Json.jNull, }; /** 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'>; + 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> = @@ -102,34 +125,38 @@ export const jMarkerSafe: Json.Safe<marker> = /** 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'), + 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 = { +export const getFunctions: Server.GetRequest<null,Json.Key<'#fct'>[]> = { kind: Server.RqKind.GET, - name: 'kernel.ast.getFunctions', + name: 'kernel.ast.getFunctions', + input: Json.jNull, + output: Json.jList(Json.jKey('#fct')), }; /** Print the AST of a function */ -export const printFunction: Server.GetRequest = { +export const printFunction: Server.GetRequest<Json.Key<'#fct'>,text> = { kind: Server.RqKind.GET, - name: 'kernel.ast.printFunction', + name: 'kernel.ast.printFunction', + input: Json.jKey('#fct'), + output: jText, }; /** AST Functions */ -export const functions: State.Array<'functions',functionsData> = { +export const functions: State.Array<'#functions',functionsData> = { signal: signalFunctions, fetch: fetchFunctions, reload: reloadFunctions, @@ -143,7 +170,7 @@ export const signalFunctions: Server.Signal = { /** Data for array rows [`functions`](#functions) */ export interface functionsData { /** Entry identifier. */ - key: Json.Key<'functions'>; + key: Json.Key<'#functions'>; /** Name */ name: string; /** Signature */ @@ -151,33 +178,51 @@ export interface functionsData { } /** Data fetcher for array [`functions`](#functions) */ -export const fetchFunctions: Server.GetRequest = { +export const fetchFunctions: Server.GetRequest<number, + { pending: number, updated: functionsData[], + removed: Json.Key<'#functions'>[], reload: boolean }> = { kind: Server.RqKind.GET, - name: 'kernel.ast.fetchFunctions', + name: 'kernel.ast.fetchFunctions', + input: Json.jNumber, + output: Json.jTry( + Json.jObject({ + pending: Json.jFail(Json.jNumber,'Number expected'), + updated: Json.jList(jFunctionsData), + removed: Json.jList(Json.jKey('#functions')), + reload: Json.jFail(Json.jBoolean,'Boolean expected'), + })), }; /** Force full reload for array [`functions`](#functions) */ -export const reloadFunctions: Server.GetRequest = { +export const reloadFunctions: Server.GetRequest<null,null> = { kind: Server.RqKind.GET, - name: 'kernel.ast.reloadFunctions', + name: 'kernel.ast.reloadFunctions', + input: Json.jNull, + output: Json.jNull, }; /** Get textual information about a marker */ -export const getInfo: Server.GetRequest = { +export const getInfo: Server.GetRequest<marker,text> = { kind: Server.RqKind.GET, - name: 'kernel.ast.getInfo', + name: 'kernel.ast.getInfo', + input: jMarker, + output: jText, }; /** Get the currently analyzed source file names */ -export const getFiles: Server.GetRequest = { +export const getFiles: Server.GetRequest<null,string[]> = { kind: Server.RqKind.GET, - name: 'kernel.ast.getFiles', + name: 'kernel.ast.getFiles', + input: Json.jNull, + output: Json.jList(Json.jString), }; /** Set the source file names to analyze. */ -export const setFiles: Server.SetRequest = { +export const setFiles: Server.SetRequest<string[],null> = { kind: Server.RqKind.SET, - name: 'kernel.ast.setFiles', + name: 'kernel.ast.setFiles', + input: Json.jList(Json.jString), + output: Json.jNull, }; /* ------------------------------------- */ diff --git a/ivette/api/kernel/project.ts b/ivette/api/kernel/project.ts index 41a0996a639..5335e9e6cc8 100644 --- a/ivette/api/kernel/project.ts +++ b/ivette/api/kernel/project.ts @@ -12,12 +12,12 @@ import * as Server from 'frama-c/server'; /** Project informations */ export type projectInfo = - { id: Json.Key<'project'>, name: string, current: boolean }; + { 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'), + id: Json.jFail(Json.jKey('#project'),'#project expected'), name: Json.jFail(Json.jString,'String expected'), current: Json.jFail(Json.jBoolean,'Boolean expected'), }); @@ -30,12 +30,12 @@ export const jProjectInfo: Json.Loose<projectInfo> = /** Request to be executed on the specified project. */ export type projectRequest = - { project: Json.Key<'project'>, request: string, data: Json.json }; + { 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'), + project: Json.jFail(Json.jKey('#project'),'#project expected'), request: Json.jFail(Json.jString,'String expected'), data: Json.jAny, }); @@ -47,45 +47,59 @@ export const jProjectRequest: Json.Loose<projectRequest> = /** Natural order for `projectRequest` */ /** Returns the current project */ -export const getCurrent: Server.GetRequest = { +export const getCurrent: Server.GetRequest<null,projectInfo> = { kind: Server.RqKind.GET, - name: 'kernel.project.getCurrent', + name: 'kernel.project.getCurrent', + input: Json.jNull, + output: jProjectInfo, }; /** Switches the current project */ -export const setCurrent: Server.SetRequest = { +export const setCurrent: Server.SetRequest<Json.Key<'#project'>,null> = { kind: Server.RqKind.SET, - name: 'kernel.project.setCurrent', + name: 'kernel.project.setCurrent', + input: Json.jKey('#project'), + output: Json.jNull, }; /** Returns the list of all projects */ -export const getList: Server.GetRequest = { +export const getList: Server.GetRequest<null,projectInfo[]> = { kind: Server.RqKind.GET, - name: 'kernel.project.getList', + name: 'kernel.project.getList', + input: Json.jNull, + output: Json.jList(jProjectInfo), }; /** Execute a GET request within the given project */ -export const getOn: Server.GetRequest = { +export const getOn: Server.GetRequest<projectRequest,Json.json> = { kind: Server.RqKind.GET, - name: 'kernel.project.getOn', + name: 'kernel.project.getOn', + input: jProjectRequest, + output: Json.jAny, }; /** Execute a SET request within the given project */ -export const setOn: Server.SetRequest = { +export const setOn: Server.SetRequest<projectRequest,Json.json> = { kind: Server.RqKind.SET, - name: 'kernel.project.setOn', + name: 'kernel.project.setOn', + input: jProjectRequest, + output: Json.jAny, }; /** Execute an EXEC request within the given project */ -export const execOn: Server.ExecRequest = { +export const execOn: Server.ExecRequest<projectRequest,Json.json> = { kind: Server.RqKind.EXEC, - name: 'kernel.project.execOn', + name: 'kernel.project.execOn', + input: jProjectRequest, + output: Json.jAny, }; /** Create a new project */ -export const create: Server.SetRequest = { +export const create: Server.SetRequest<string,projectInfo> = { kind: Server.RqKind.SET, - name: 'kernel.project.create', + name: 'kernel.project.create', + input: Json.jString, + output: jProjectInfo, }; /* ------------------------------------- */ diff --git a/ivette/api/kernel/properties.ts b/ivette/api/kernel/properties.ts index 05d00856eda..696f28775e0 100644 --- a/ivette/api/kernel/properties.ts +++ b/ivette/api/kernel/properties.ts @@ -9,7 +9,13 @@ import * as Json from 'dome/data/json'; import * as Server from 'frama-c/server'; +import { byTag } from 'api/kernel/data'; +import { jTag } from 'api/kernel/data'; +import { jTagSafe } from 'api/kernel/data'; import { tag } from 'api/kernel/data'; +import { bySource } from 'api/kernel/services'; +import { jSource } from 'api/kernel/services'; +import { jSourceSafe } from 'api/kernel/services'; import { source } from 'api/kernel/services'; /** Property Kinds */ @@ -94,9 +100,11 @@ export const jPropKind: Json.Loose<propKind> = Json.jEnum(propKind); /** Natural order for `propKind` */ /** Registered tags for the above type. */ -export const propKindTags: Server.GetRequest = { +export const propKindTags: Server.GetRequest<null,tag[]> = { kind: Server.RqKind.GET, - name: 'kernel.properties.propKindTags', + name: 'kernel.properties.propKindTags', + input: Json.jNull, + output: Json.jList(jTag), }; /** Property Status (consolidated) */ @@ -135,9 +143,11 @@ export const jPropStatus: Json.Loose<propStatus> = Json.jEnum(propStatus); /** Natural order for `propStatus` */ /** Registered tags for the above type. */ -export const propStatusTags: Server.GetRequest = { +export const propStatusTags: Server.GetRequest<null,tag[]> = { kind: Server.RqKind.GET, - name: 'kernel.properties.propStatusTags', + name: 'kernel.properties.propStatusTags', + input: Json.jNull, + output: Json.jList(jTag), }; /** Alarm Kinds */ @@ -190,13 +200,15 @@ export const jAlarms: Json.Loose<alarms> = Json.jEnum(alarms); /** Natural order for `alarms` */ /** Registered tags for the above type. */ -export const alarmsTags: Server.GetRequest = { +export const alarmsTags: Server.GetRequest<null,tag[]> = { kind: Server.RqKind.GET, - name: 'kernel.properties.alarmsTags', + name: 'kernel.properties.alarmsTags', + input: Json.jNull, + output: Json.jList(jTag), }; /** Status of Registered Properties */ -export const status: State.Array<'status',statusData> = { +export const status: State.Array<'#status',statusData> = { signal: signalStatus, fetch: fetchStatus, reload: reloadStatus, @@ -210,7 +222,7 @@ export const signalStatus: Server.Signal = { /** Data for array rows [`status`](#status) */ export interface statusData { /** Entry identifier. */ - key: Json.Key<'status'>; + key: Json.Key<'#status'>; /** Full description */ descr: string; /** Kind */ @@ -220,9 +232,9 @@ export interface statusData { /** Status */ status: propStatus; /** Function */ - function?: Json.Key<'fct'>; + function?: Json.Key<'#fct'>; /** Instruction */ - kinstr?: Json.Key<'stmt'>; + kinstr?: Json.Key<'#stmt'>; /** Position */ source: source; /** Alarm name (if the property is an alarm) */ @@ -234,15 +246,27 @@ export interface statusData { } /** Data fetcher for array [`status`](#status) */ -export const fetchStatus: Server.GetRequest = { +export const fetchStatus: Server.GetRequest<number, + { pending: number, updated: statusData[], removed: Json.Key<'#status'>[], + reload: boolean }> = { kind: Server.RqKind.GET, - name: 'kernel.properties.fetchStatus', + name: 'kernel.properties.fetchStatus', + input: Json.jNumber, + output: Json.jTry( + Json.jObject({ + pending: Json.jFail(Json.jNumber,'Number expected'), + updated: Json.jList(jStatusData), + removed: Json.jList(Json.jKey('#status')), + reload: Json.jFail(Json.jBoolean,'Boolean expected'), + })), }; /** Force full reload for array [`status`](#status) */ -export const reloadStatus: Server.GetRequest = { +export const reloadStatus: Server.GetRequest<null,null> = { kind: Server.RqKind.GET, - name: 'kernel.properties.reloadStatus', + name: 'kernel.properties.reloadStatus', + input: Json.jNull, + output: Json.jNull, }; /* ------------------------------------- */ diff --git a/ivette/api/kernel/services.ts b/ivette/api/kernel/services.ts index db7c4f085df..56348fad9fc 100644 --- a/ivette/api/kernel/services.ts +++ b/ivette/api/kernel/services.ts @@ -9,18 +9,33 @@ import * as Json from 'dome/data/json'; import * as Server from 'frama-c/server'; +import { byTag } from 'api/kernel/data'; +import { jTag } from 'api/kernel/data'; +import { jTagSafe } from 'api/kernel/data'; import { tag } from 'api/kernel/data'; /** Frama-C Kernel configuration */ -export const getConfig: Server.GetRequest = { +export const getConfig: Server.GetRequest<null, + { pluginpath: string[], libdir: string, datadir: string, version: string } + > = { kind: Server.RqKind.GET, - name: 'kernel.services.getConfig', + name: 'kernel.services.getConfig', + input: Json.jNull, + output: Json.jTry( + Json.jObject({ + pluginpath: Json.jList(Json.jString), + libdir: Json.jFail(Json.jString,'String expected'), + datadir: Json.jFail(Json.jString,'String expected'), + version: Json.jFail(Json.jString,'String expected'), + })), }; /** Load a save file. Returns an error, if not successfull. */ -export const load: Server.SetRequest = { +export const load: Server.SetRequest<string,string | undefined> = { kind: Server.RqKind.SET, - name: 'kernel.services.load', + name: 'kernel.services.load', + input: Json.jString, + output: Json.jString, }; /** Source file positions. */ @@ -67,9 +82,11 @@ export const jLogkind: Json.Loose<logkind> = Json.jEnum(logkind); /** Natural order for `logkind` */ /** Registered tags for the above type. */ -export const logkindTags: Server.GetRequest = { +export const logkindTags: Server.GetRequest<null,tag[]> = { kind: Server.RqKind.GET, - name: 'kernel.services.logkindTags', + name: 'kernel.services.logkindTags', + input: Json.jNull, + output: Json.jList(jTag), }; /** Message event record. */ @@ -102,15 +119,19 @@ export const jLog: Json.Loose<log> = Json.jTry(jLogSafe); /** Natural order for `log` */ /** Turn logs monitoring on/off */ -export const setLogs: Server.SetRequest = { +export const setLogs: Server.SetRequest<boolean,null> = { kind: Server.RqKind.SET, - name: 'kernel.services.setLogs', + name: 'kernel.services.setLogs', + input: Json.jBoolean, + output: Json.jNull, }; /** Flush the last emitted logs since last call (max 100) */ -export const getLogs: Server.GetRequest = { +export const getLogs: Server.GetRequest<null,log[]> = { kind: Server.RqKind.GET, - name: 'kernel.services.getLogs', + name: 'kernel.services.getLogs', + input: Json.jNull, + output: Json.jList(jLog), }; /* ------------------------------------- */ diff --git a/ivette/api/server_tsc.ml b/ivette/api/server_tsc.ml index a5139d848c6..a50958b176c 100644 --- a/ivette/api/server_tsc.ml +++ b/ivette/api/server_tsc.ml @@ -53,11 +53,15 @@ let makeDescr ?(indent="") fmt descr = if descr <> [] then Format.fprintf fmt "%s/** @[<hov 0>%a@] */@." indent pp_descr descr +let getSelf = function + | None -> Self.fatal "Unexpected recursive type" + | Some id -> id + (* -------------------------------------------------------------------------- *) (* --- Jtype Generator --- *) (* -------------------------------------------------------------------------- *) -let makeJtype ~self ~names = +let makeJtype ?self ~names = let open Pkg in let pp_ident fmt id = match IdMap.find id names with @@ -65,14 +69,14 @@ 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.name + | Jself -> Format.pp_print_string fmt (getSelf self).name | Jnull -> Format.pp_print_string fmt "null" | Jnumber -> Format.pp_print_string fmt "number" | Jboolean -> Format.pp_print_string fmt "boolean" | 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 - | Jdict(kd,js) -> Format.fprintf fmt "Json.Dict<'%s',%a>" kd pp js + | Jkey kd -> Format.fprintf fmt "Json.Key<'#%s'>" kd + | Jindex kd -> Format.fprintf fmt "Json.Index<'#%s'>" kd + | 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 -> @@ -93,8 +97,8 @@ let makeJtype ~self ~names = (* -------------------------------------------------------------------------- *) 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 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) @@ -147,10 +151,10 @@ let jtuple ~makeSafe fmt jts = Format.fprintf fmt "@]@,)@]" ; end -let rec makeDecoder ~safe ~self ~names fmt js = +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 + 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" @@ -158,13 +162,13 @@ let rec makeDecoder ~safe ~self ~names fmt js = | 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 + | 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 self) + | Jself -> jcall names fmt (Pkg.Derived.decode ~safe (getSelf self)) | Joption js -> makeLoose fmt js | Jdict(kd,js) -> - Format.fprintf fmt "@[<hov 2>Json.jDict('%s',@,%a)@]" kd makeLoose 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 -> @@ -172,7 +176,7 @@ let rec makeDecoder ~safe ~self ~names fmt js = 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 + 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 @@ -191,6 +195,16 @@ let makeRootDecoder ~safe ~self ~names fmt js = (String.capitalize_ascii self.name) | _ -> makeDecoder ~safe ~self ~names fmt js +(* -------------------------------------------------------------------------- *) +(* --- Parameter Decoder --- *) +(* -------------------------------------------------------------------------- *) + +let typeOfParam = function + | Pkg.P_value js -> js + | Pkg.P_named fjs -> + let field fd = fd.Pkg.fd_name , fd.Pkg.fd_type in + Jrecord (List.map field fjs) + (* -------------------------------------------------------------------------- *) (* --- Declaration Generator --- *) (* -------------------------------------------------------------------------- *) @@ -224,20 +238,27 @@ let makeDeclaration fmt names d = Format.fprintf fmt " %s = '%s';@\n" tag tag ; ) tgs ; Format.fprintf fmt "}@\n" ; + | D_signal -> + 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_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.name prefix ; + 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 + Format.fprintf fmt + "@[<hov 2>export const %s: Server.%sRequest<@,%a,@,%a@,> = {@]@\n" + self.name prefix jtype input jtype output ; 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.name ; - Format.fprintf fmt " name: '%s',@\n" (Pkg.name_of_ident d.d_ident) ; + Format.fprintf fmt " name: '%s',@\n" (Pkg.name_of_ident d.d_ident) ; + Format.fprintf fmt " input: %a,@\n" makeParam input ; + Format.fprintf fmt " output: %a,@\n" makeParam output ; Format.fprintf fmt "};@\n" ; | D_value js -> - Format.fprintf fmt "export const %s: State.Value<%a> = {@\n" + Format.fprintf fmt + "@[<hov 2>export const %s: State.Value<@,%a@,> = {@]@\n" self.name jtype js ; Format.fprintf fmt " signal: %a,@\n" (jcall names) (Pkg.Derived.signal self) ; @@ -245,7 +266,8 @@ let makeDeclaration fmt names d = (jcall names) (Pkg.Derived.getter self) ; Format.fprintf fmt "};@\n" ; | D_state js -> - Format.fprintf fmt "export const %s: State.State<%a> = {@\n" + Format.fprintf fmt + "@[<hov 2>export const %s: State.State<@,%a@,> = {@]@\n" self.name jtype js ; Format.fprintf fmt " signal: %a,@\n" (jcall names) (Pkg.Derived.signal self) ; @@ -256,7 +278,8 @@ let makeDeclaration fmt names d = 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" + Format.fprintf fmt + "@[<hov 2>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) ; @@ -266,11 +289,13 @@ let makeDeclaration fmt names d = (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" + 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" + 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 _ -> () diff --git a/src/plugins/server/package.ml b/src/plugins/server/package.ml index 29f47cd79b6..837861f6bb1 100644 --- a/src/plugins/server/package.ml +++ b/src/plugins/server/package.ml @@ -250,6 +250,32 @@ let pp_pkgname fmt { p_plugin ; p_package } = ( pp_plugin fmt p_plugin ; List.iter (pp_step fmt) p_package ) +(* -------------------------------------------------------------------------- *) +(* --- Derived Names --- *) +(* -------------------------------------------------------------------------- *) + +let derived ?prefix ?suffix id = + let capitalize = String.capitalize_ascii in + match prefix , suffix with + | None , None -> id + | Some p , None -> { id with name = p ^ capitalize id.name } + | None , Some q -> { id with name = id.name ^ q } + | Some p , Some q -> { id with name = p ^ capitalize id.name ^ q } + +module Derived = +struct + 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 + (* -------------------------------------------------------------------------- *) (* --- Visitors --- *) (* -------------------------------------------------------------------------- *) @@ -260,7 +286,13 @@ let rec visit_jtype fn = function | 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 | Jenum id -> fn id + | Jdata id | Jenum id -> + begin + fn id ; + fn (Derived.safe id) ; + fn (Derived.loose id) ; + fn (Derived.order id) ; + end let visit_field f { fd_type } = visit_jtype f fd_type @@ -293,32 +325,6 @@ let resolve ?(keywords=[]) pkg = visit_package_used (Scope.use scope) pkg ; Scope.resolve scope -(* -------------------------------------------------------------------------- *) -(* --- Derived Names --- *) -(* -------------------------------------------------------------------------- *) - -let derived ?prefix ?suffix id = - let capitalize = String.capitalize_ascii in - match prefix , suffix with - | None , None -> id - | Some p , None -> { id with name = p ^ capitalize id.name } - | None , Some q -> { id with name = id.name ^ q } - | Some p , Some q -> { id with name = p ^ capitalize id.name ^ q } - -module Derived = -struct - 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 - (* -------------------------------------------------------------------------- *) (* --- Server API --- *) (* -------------------------------------------------------------------------- *) -- GitLab