Skip to content
Snippets Groups Projects
Commit 3110035e authored by Loïc Correnson's avatar Loïc Correnson
Browse files

[server] generator for enumerated values

Application to logs, properties kind & status
parent dd85a15e
No related branches found
No related tags found
No related merge requests found
...@@ -94,10 +94,6 @@ module Jtext : S with type t = json (** Rich text encoding, see [Jbuffer] *) ...@@ -94,10 +94,6 @@ module Jtext : S with type t = json (** Rich text encoding, see [Jbuffer] *)
(** {2 Records} *) (** {2 Records} *)
(* -------------------------------------------------------------------------- *) (* -------------------------------------------------------------------------- *)
type 'a record (** Records of type 'a *)
type 'a signature (** Opened signature for record of type ['a] *)
type ('a,'b) field (** Field of type ['b] for a record of type ['a] *)
(** Record factory. (** Record factory.
You shall start by declaring a (ghost) type [r] and call You shall start by declaring a (ghost) type [r] and call
...@@ -122,6 +118,10 @@ type ('a,'b) field (** Field of type ['b] for a record of type ['a] *) ...@@ -122,6 +118,10 @@ type ('a,'b) field (** Field of type ['b] for a record of type ['a] *)
module Record : module Record :
sig sig
type 'a record (** Records of type 'a *)
type 'a signature (** Opened signature for record of type ['a] *)
type ('a,'b) field (** Field of type ['b] for a record of type ['a] *)
(** Data with [type t = r record]. (** Data with [type t = r record].
Also contains getters and setters for fields. *) Also contains getters and setters for fields. *)
module type S = module type S =
...@@ -149,7 +149,72 @@ sig ...@@ -149,7 +149,72 @@ sig
('r,'a option) field ('r,'a option) field
(** Publish and close an opened record *) (** Publish and close an opened record *)
val publish : 'a signature -> (module S with type r = 'a) val publish : 'a signature ->
(module S with type r = 'a)
end
(* -------------------------------------------------------------------------- *)
(** {2 Enums} *)
(* -------------------------------------------------------------------------- *)
(** Enum factory.
You shall start by declaring a dictionnary with
[Enum.dictionary] for your values.
Then, populate the dictionary with [Enum.tag] values.
Finally, you shall call [Enum.publish] to obtain a new data module
for your type.
You have two options for computing tags: either you provide values
when declaring tags, and these tags will be associated to registered
values for both directions;
alternatively you might provide a [~tag] function to [Enum.publish].
The difficulty when providing values only at tag definition is to ensure
that all possible value has been registered.
The conversion values from and to json may fail when no value has been
registered with tags.
*)
module Enum :
sig
type 'a dictionary
type 'a tag
type 'a prefix = string -> 'a tag
val name : 'a tag -> string
(** Creates an opened, empty dictionnary. *)
val dictionary :
page:Doc.page -> name:string -> descr:Markdown.text ->
unit -> 'a dictionary
(** Register a new tag in the dictionnary.
The provided value, if any, will be used for decoding json tags.
If would be used also for encoding values to json tags if no [~tag]
function is provided when publishing the dictionnary.
Registered values must be hashable with [Hashtbl.hash] function. *)
val tag : 'a dictionary ->
name:string -> descr:Markdown.text -> ?value:'a ->
unit -> 'a tag
(** Register a new prefix tag in the dictionnary.
To decoding from json is provided to prefix tags.
Encoding is done by emitting tags with form ['prefix:*'].
The variable part of the prefix is documented as ['prefix:xxx']
when [~var:"xxx"] is provided. *)
val prefix : 'a dictionary ->
prefix:string -> ?var:string -> descr:Markdown.text -> unit -> 'a prefix
(** Publish the dictionnary. To more tag nor prefix can be added after.
If no [~tag] function is provided, registered values with tags
are used. *)
val publish : 'a dictionary ->
?tag:('a -> 'a tag) ->
unit -> (module S with type t = 'a)
end end
...@@ -196,19 +261,6 @@ end ...@@ -196,19 +261,6 @@ end
(** Builds a {i projectified} index on types with {i unique} identifiers *) (** Builds a {i projectified} index on types with {i unique} identifiers *)
module Identified(A : IdentifiedType) : Index with type t = A.t module Identified(A : IdentifiedType) : Index with type t = A.t
(* -------------------------------------------------------------------------- *)
(** {2 Dictionary} *)
(* -------------------------------------------------------------------------- *)
module type Enum =
sig
type t
val values : (t * string * Markdown.text) list
include Info
end
module Dictionary(E : Enum) : S_collection with type t = E.t
(* -------------------------------------------------------------------------- *) (* -------------------------------------------------------------------------- *)
(** {2 Error handling} *) (** {2 Error handling} *)
(* -------------------------------------------------------------------------- *) (* -------------------------------------------------------------------------- *)
......
...@@ -163,58 +163,6 @@ let () = Request.register ~page ...@@ -163,58 +163,6 @@ let () = Request.register ~page
~input:(module Kf) ~output:(module Jtext) ~input:(module Kf) ~output:(module Jtext)
(fun kf -> Jbuffer.to_json PP.pp_global (Kernel_function.get_global kf)) (fun kf -> Jbuffer.to_json PP.pp_global (Kernel_function.get_global kf))
(* -------------------------------------------------------------------------- *)
(* --- Properties --- *)
(* -------------------------------------------------------------------------- *)
module Property = struct
type p
let signature =
Record.signature ~page ~name:"property"
~descr:(Md.plain "logical property") ()
let name = Record.field signature ~name:"name"
~descr:(Md.plain "name") (module Jstring)
let property = Record.field signature ~name:"property"
~descr:(Md.plain "logical property") (module Jstring)
let status = Record.field signature ~name:"status"
~descr:(Md.plain "logical status") (module Jstring)
let file = Record.field signature ~name:"file"
~descr:(Md.plain "file") (module Jstring)
let kf = Record.field signature ~name:"function"
~descr:(Md.plain "kernel function") (module Kf.Joption)
let kinstr = Record.field signature ~name:"kinstr"
~descr:(Md.plain "kinstr") (module Ki)
module R = (val (Record.publish signature) : Record.S with type r = p)
include R
let make ip =
let st = Property_status.Feedback.get ip in
let st = Format.asprintf "%a" Property_status.Feedback.pretty st in
let p = Format.asprintf "%a" Property.pretty ip in
let loc = Property.location ip in
let path = Filepath.(Normalized.to_pretty_string (fst loc).pos_path) in
default |> set property p |> set status st
|> set kf (Property.get_kf ip)
|> set kinstr (Property.get_kinstr ip)
|> set name (Property.Names.get_prop_name_id ip)
|> set file path
end
let get_properties () =
Property_status.fold (fun ip acc -> Property.make ip :: acc) []
let () =
Request.register
~page
~kind:`GET
~name:"kernel.ast.getProperties"
~descr:(Md.plain "Collect all logical properties")
~input:(module Junit)
~output:(module Jlist (Property))
get_properties
(* -------------------------------------------------------------------------- *) (* -------------------------------------------------------------------------- *)
(* --- Files --- *) (* --- Files --- *)
(* -------------------------------------------------------------------------- *) (* -------------------------------------------------------------------------- *)
......
...@@ -110,21 +110,35 @@ module LogSource = Collection(RawSource) ...@@ -110,21 +110,35 @@ module LogSource = Collection(RawSource)
module RawKind = module RawKind =
struct struct
type t = Log.kind let kinds = Enum.dictionary ~page
let page = page ~name:"kind"
let name = "kind" ~descr:(Md.plain "Frama-C message category.")
let descr = Md.plain "Frama-C message category." ()
let values = [
Log.Error, "ERROR", Md.plain "User Error" ; let t_kind value name descr =
Log.Warning, "WARNING", Md.plain "User Warning" ; Enum.tag kinds ~name ~descr:(Md.plain descr) ~value ()
Log.Feedback, "FEEDBACK", Md.plain "Analyzer Feedback" ;
Log.Result, "RESULT", Md.plain "Analyzer Result" ; let t_error = t_kind Log.Error "ERROR" "User Error"
Log.Failure, "FAILURE", Md.plain "Analyzer Failure" ; let t_warning = t_kind Log.Warning "WARNING" "User Warning"
Log.Debug, "DEBUG", Md.plain "Analyser Debug" ; let t_feedback = t_kind Log.Feedback "FEEDBACK" "Plugin Feedback"
] let t_result = t_kind Log.Result "RESULT" "Plugin Result"
let t_failure = t_kind Log.Failure "FAILURE" "Plugin Failure"
let t_debug = t_kind Log.Debug "DEBUG" "Analyser Debug"
let tag = function
| Log.Error -> t_error
| Log.Warning -> t_warning
| Log.Feedback -> t_feedback
| Log.Result -> t_result
| Log.Failure -> t_failure
| Log.Debug -> t_debug
let data = Enum.publish kinds ~tag ()
include (val data : S with type t = Log.kind)
end end
module LogKind = Dictionary(RawKind) module LogKind = Collection(RawKind)
(* -------------------------------------------------------------------------- *) (* -------------------------------------------------------------------------- *)
(* --- Log Events --- *) (* --- Log Events --- *)
...@@ -135,7 +149,7 @@ struct ...@@ -135,7 +149,7 @@ struct
type rlog type rlog
let jlog : rlog signature = Record.signature ~page let jlog : rlog Record.signature = Record.signature ~page
~name:"log" ~descr:(Md.plain "Message event record.") () ~name:"log" ~descr:(Md.plain "Message event record.") ()
let kind = Record.field jlog ~name:"kind" let kind = Record.field jlog ~name:"kind"
......
...@@ -36,43 +36,159 @@ let page = Doc.page `Kernel ~title:"Property Services" ~filename:"properties.md" ...@@ -36,43 +36,159 @@ let page = Doc.page `Kernel ~title:"Property Services" ~filename:"properties.md"
module PropKind = module PropKind =
struct struct
type t = string let kinds = Enum.dictionary ~page
let syntax = Sy.publish ~page
~name:"propkind" ~name:"propkind"
~descr:(Md.plain "Property Kind") ~descr:(Md.plain "Property Kind")
~synopsis:Sy.string () ()
let t_kind name descr = Enum.tag kinds ~name ~descr:(Md.plain descr) ()
let t_clause name = t_kind name (Printf.sprintf "Clause `@%s`" name)
let t_loop name =
t_kind ("loop-" ^ name) (Printf.sprintf "Clause `@loop %s`" name)
let t_behavior = t_kind "behavior" "Contract behavior"
let t_complete = t_kind "complete" "Complete behaviors clause"
let t_disjoint = t_kind "disjoint" "Disjoint behaviors clause"
let t_assumes = t_clause "assumes"
let t_requires = t_clause "requires"
let t_breaks = t_clause "breaks"
let t_continues = t_clause "continues"
let t_returns = t_clause "returns"
let t_exits = t_clause "exits"
let t_ensures = t_clause "ensures"
let t_terminates = t_clause "terminates"
let t_allocates = t_clause "allocates"
let t_decreases = t_clause "decreases"
let t_assigns = t_clause "assigns"
let t_froms = t_kind "froms" "Clause `@assigns … \\from …`"
let t_ext = Enum.prefix kinds ~prefix:"ext" ~var:"<clause>"
~descr:(Md.plain "ACSL extension `<clause>`") ()
let t_assert = t_clause "assert"
let t_loop_invariant = t_loop "invariant"
let t_loop_assigns = t_loop "assigns"
let t_loop_variant = t_loop "variant"
let t_loop_allocates = t_loop "allocates"
let t_loop_pragma = t_loop "pragma"
let t_loop_ext = Enum.prefix kinds ~prefix:"loop-ext" ~var:"<clause>"
~descr:(Md.plain "ACSL loop extension `loop <clause>`") ()
let t_reachable = t_kind "reachable" "Reachable statement"
let t_code_contract = t_kind "code-contract" "Statement Contract"
let t_code_invariant = t_kind "code-invariant" "Generalized loop invariant"
let t_type_invariant = t_kind "type-invariant" "Type invariant"
let t_global_invariant = t_kind "global-invariant" "Global invariant"
let t_axiomatic = t_kind "axiomatic" "Axiomatic definitions"
let t_axiom = t_kind "axiom" "Logical axiom"
let t_lemma = t_kind "lemma" "Logical lemma"
let t_other = Enum.prefix kinds ~prefix:"prop" ~var:"<prop>"
~descr:(Md.plain "Plugin Specific properties") ()
open Property open Property
let kind = function
| IPPredicate _ -> "predicate" let rec tag = function
| IPExtended { ie_ext={ ext_name } } -> ext_name | IPPredicate { ip_kind } ->
| IPAxiomatic _ -> "axiomatic" begin match ip_kind with
| IPAxiom _ -> "axiom" | PKRequires _ -> t_requires
| IPLemma _ -> "lemma" | PKAssumes _ -> t_assumes
| IPBehavior _ -> "behavior" | PKEnsures(_,Normal) -> t_ensures
| IPComplete _ -> "complete" | PKEnsures(_,Exits) -> t_exits
| IPDisjoint _ -> "disjoint" | PKEnsures(_,Breaks) -> t_breaks
| PKEnsures(_,Continues) -> t_continues
| PKEnsures(_,Returns) -> t_returns
| PKTerminates -> t_terminates
end
| IPExtended { ie_ext={ ext_name } } -> t_ext ext_name
| IPAxiomatic _ -> t_axiomatic
| IPAxiom _ -> t_axiom
| IPLemma _ -> t_lemma
| IPBehavior _ -> t_behavior
| IPComplete _ -> t_complete
| IPDisjoint _ -> t_disjoint
| IPCodeAnnot { ica_ca={ annot_content } } -> | IPCodeAnnot { ica_ca={ annot_content } } ->
begin match annot_content with begin match annot_content with
| AAssert _ -> "assert" | AAssert _ -> t_assert
| AStmtSpec _ -> "stmt-contract" | AStmtSpec _ -> t_code_contract
| AInvariant(_,false,_) -> "code-invariant" | AInvariant(_,false,_) -> t_code_invariant
| AInvariant(_,true,_) -> "loop-invariant" | AInvariant(_,true,_) -> t_loop_invariant
| AVariant _ -> "loop-variant" | AVariant _ -> t_loop_variant
| AAssigns _ -> "loop-assigns" | AAssigns _ -> t_loop_assigns
| AAllocation _ -> "loop-allocatation" | AAllocation _ -> t_loop_allocates
| APragma _ -> "loop-pragma" | APragma _ -> t_loop_pragma
| AExtended(_,_,{ext_name}) -> "loop-" ^ ext_name | AExtended(_,_,{ext_name}) -> t_loop_ext ext_name
end end
| IPAllocation _ -> "allocation" | IPAllocation _ -> t_allocates
| IPAssigns _ -> "assigns" | IPAssigns _ -> t_assigns
| IPFrom _ -> "froms" | IPFrom _ -> t_froms
| IPDecrease _ -> "decrease" | IPDecrease _ -> t_decreases
| IPReachable _ -> "reachable" | IPReachable _ -> t_reachable
| IPPropertyInstance _ -> "instance" | IPPropertyInstance { ii_ip } -> tag ii_ip
| IPTypeInvariant _ -> "type-invariant" | IPTypeInvariant _ -> t_type_invariant
| IPGlobalInvariant _ -> "invariant" | IPGlobalInvariant _ -> t_global_invariant
| IPOther { io_name } -> io_name | IPOther { io_name } -> t_other io_name
let to_json = Jstring.to_json
let data = Enum.publish kinds ~tag ()
include (val data : S with type t = Property.t)
end
(* -------------------------------------------------------------------------- *)
(* --- Property Status --- *)
(* -------------------------------------------------------------------------- *)
module PropStatus =
struct
let status = Enum.dictionary ~page ~name:"status"
~descr:(Md.plain "Property Status (consolidated)") ()
let t_status value name descr =
Enum.tag status ~name ~descr:(Md.plain descr) ~value ()
open Property_status.Feedback
let t_unknown =
t_status Unknown "unknown" "Unknown status"
let t_never_tried =
t_status Never_tried "never-tried" "Unknown status (never tried)"
let t_inconsistent =
t_status Inconsistent "inconsistent" "Inconsistent status"
let t_valid =
t_status Valid "valid" "Valid property"
let t_valid_under_hyp =
t_status Valid_under_hyp "valid_under_hyp" "Valid (under hypotheses)"
let t_considered_valid =
t_status Considered_valid "considered_valid" "Valid (external assumption)"
let t_invalid =
t_status Invalid "invalid" "Invalid property (counter example found)"
let t_invalid_under_hyp =
t_status Invalid_under_hyp "invalid_under_hyp" "Invalid property (under hypotheses)"
let t_invalid_but_dead =
t_status Invalid_but_dead "invalid_but_dead" "Dead property (but invalid)"
let t_valid_but_dead =
t_status Valid_but_dead "valid_but_dead" "Dead property (but valid)"
let t_unknown_but_dead =
t_status Unknown_but_dead "unknown_but_dead" "Dead property (but unknown)"
let tag = function
| Valid -> t_valid
| Invalid -> t_invalid
| Unknown -> t_unknown
| Never_tried -> t_never_tried
| Valid_under_hyp -> t_valid_under_hyp
| Valid_but_dead -> t_valid_but_dead
| Considered_valid -> t_considered_valid
| Invalid_under_hyp -> t_invalid_under_hyp
| Invalid_but_dead -> t_invalid_but_dead
| Unknown_but_dead -> t_unknown_but_dead
| Inconsistent -> t_inconsistent
let data = Enum.publish status ~tag ()
include (val data : S with type t = Property_status.Feedback.t)
end end
(* -------------------------------------------------------------------------- *) (* -------------------------------------------------------------------------- *)
...@@ -89,14 +205,12 @@ let () = States.column ~model ~name:"descr" ...@@ -89,14 +205,12 @@ let () = States.column ~model ~name:"descr"
let () = States.column ~model ~name:"kind" let () = States.column ~model ~name:"kind"
~descr:(Md.plain "Kind") ~descr:(Md.plain "Kind")
~data:(module PropKind) ~data:(module PropKind)
~get:(PropKind.kind) () ~get:(fun ip -> ip) ()
let () = States.column ~model ~name:"status" let () = States.column ~model ~name:"status"
~descr:(Md.plain "Status") ~descr:(Md.plain "Status")
~data:(module Jstring) ~data:(module PropStatus)
~get:(fun ip -> ~get:(Property_status.Feedback.get) ()
let st = Property_status.Feedback.get ip
in Format.asprintf "%a" Property_status.Feedback.pretty st) ()
let () = States.column ~model ~name:"function" let () = States.column ~model ~name:"function"
~descr:(Md.plain "Function") ~descr:(Md.plain "Function")
......
...@@ -205,7 +205,11 @@ let param (type a b) (s : (unit,b) signature) ~name ~descr ...@@ -205,7 +205,11 @@ let param (type a b) (s : (unit,b) signature) ~name ~descr
?default (input : a input) : a param = ?default (input : a input) : a param =
let module D = (val input) in let module D = (val input) in
let syntax = if default = None then D.syntax else Syntax.option D.syntax in let syntax = if default = None then D.syntax else Syntax.option D.syntax in
let fd = Syntax.{ name ; syntax ; descr } in let fd = Syntax.{
fd_name = name ;
fd_syntax = syntax ;
fd_descr = descr ;
} in
s.input <- Pfields (fd :: fds_input s) ; s.input <- Pfields (fd :: fds_input s) ;
fun rq -> fun rq ->
try D.of_json (Fmap.find name rq.param) try D.of_json (Fmap.find name rq.param)
...@@ -217,7 +221,11 @@ let param (type a b) (s : (unit,b) signature) ~name ~descr ...@@ -217,7 +221,11 @@ let param (type a b) (s : (unit,b) signature) ~name ~descr
let param_opt (type a b) (s : (unit,b) signature) ~name ~descr let param_opt (type a b) (s : (unit,b) signature) ~name ~descr
(input : a input) : a option param = (input : a input) : a option param =
let module D = (val input) in let module D = (val input) in
let fd = Syntax.{ name ; syntax = Syntax.option D.syntax ; descr } in let fd = Syntax.{
fd_name = name ;
fd_syntax = Syntax.option D.syntax ;
fd_descr = descr ;
} in
s.input <- Pfields (fd :: fds_input s) ; s.input <- Pfields (fd :: fds_input s) ;
fun rq -> fun rq ->
try Some(D.of_json (Fmap.find name rq.param)) try Some(D.of_json (Fmap.find name rq.param))
...@@ -238,7 +246,11 @@ let fds_output s : Syntax.field list = ...@@ -238,7 +246,11 @@ let fds_output s : Syntax.field list =
let result (type a b) (s : (a,unit) signature) ~name ~descr let result (type a b) (s : (a,unit) signature) ~name ~descr
?default (output : b output) : b result = ?default (output : b output) : b result =
let module D = (val output) in let module D = (val output) in
let fd = Syntax.{ name ; syntax = D.syntax ; descr } in let fd = Syntax.{
fd_name = name ;
fd_syntax = D.syntax ;
fd_descr = descr ;
} in
s.output <- Rfields (fd :: fds_output s) ; s.output <- Rfields (fd :: fds_output s) ;
begin begin
match default with match default with
...@@ -250,7 +262,11 @@ let result (type a b) (s : (a,unit) signature) ~name ~descr ...@@ -250,7 +262,11 @@ let result (type a b) (s : (a,unit) signature) ~name ~descr
let result_opt (type a b) (s : (a,unit) signature) ~name ~descr let result_opt (type a b) (s : (a,unit) signature) ~name ~descr
(output : b output) : b option result = (output : b output) : b option result =
let module D = (val output) in let module D = (val output) in
let fd = Syntax.{ name ; syntax = option D.syntax ; descr } in let fd = Syntax.{
fd_name = name ;
fd_syntax = option D.syntax ;
fd_descr = descr ;
} in
s.output <- Rfields (fd :: fds_output s) ; s.output <- Rfields (fd :: fds_output s) ;
fun rq opt -> fun rq opt ->
match opt with None -> () | Some v -> match opt with None -> () | Some v ->
......
...@@ -98,9 +98,13 @@ let column (type a b) ~(model : a model) ~name ~descr ...@@ -98,9 +98,13 @@ let column (type a b) ~(model : a model) ~name ~descr
let module D = (val data) in let module D = (val data) in
if name = "key" || name = "index" then if name = "key" || name = "index" then
raise (Invalid_argument "Server.States.column: invalid name") ; raise (Invalid_argument "Server.States.column: invalid name") ;
if List.exists (fun (fd,_) -> fd.Syntax.name = name) !model then if List.exists (fun (fd,_) -> fd.Syntax.fd_name = name) !model then
raise (Invalid_argument "Server.States.column: duplicate name") ; raise (Invalid_argument "Server.States.column: duplicate name") ;
let fd = Syntax.{ name ; syntax = D.syntax ; descr } in let fd = Syntax.{
fd_name = name ;
fd_syntax = D.syntax ;
fd_descr = descr ;
} in
model := (fd , fun a -> D.to_json (get a)) :: !model model := (fd , fun a -> D.to_json (get a)) :: !model
module Kmap = Map.Make(String) module Kmap = Map.Make(String)
...@@ -257,12 +261,12 @@ let register_array ~page ~name ~descr ?(details=[]) ~key ...@@ -257,12 +261,12 @@ let register_array ~page ~name ~descr ?(details=[]) ~key
let columns = !model in let columns = !model in
let description = [ let description = [
Block [Text descr] ; Block [Text descr] ;
Syntax.fields ~title:(Printf.sprintf "Array %s" name) Syntax.fields ~title:"Columns"
begin begin
Syntax.{ Syntax.{
name="key" ; fd_name = "key" ;
syntax=Syntax.ident ; fd_syntax = Syntax.ident ;
descr=plain "entry identifier" ; fd_descr = plain "entry identifier" ;
} :: List.rev (List.map fst columns) } :: List.rev (List.map fst columns)
end ; end ;
Block details Block details
...@@ -270,7 +274,7 @@ let register_array ~page ~name ~descr ?(details=[]) ~key ...@@ -270,7 +274,7 @@ let register_array ~page ~name ~descr ?(details=[]) ~key
let mref = Doc.publish ~page:page ~name:name ~title ~index description [] in let mref = Doc.publish ~page:page ~name:name ~title ~index description [] in
let signal = Request.signal ~page ~name:(name ^ ".sig") let signal = Request.signal ~page ~name:(name ^ ".sig")
~descr:(plain "Signal for array " @ href mref) () in ~descr:(plain "Signal for array " @ href mref) () in
let getter = List.map (fun (fd,to_js) -> fd.Syntax.name , to_js) columns in let getter = List.map Syntax.(fun (fd,to_js) -> fd.fd_name , to_js) columns in
let array = { let array = {
key ; iter ; getter ; signal ; key ; iter ; getter ; signal ;
current = None ; projects = Hashtbl.create 0 current = None ; projects = Hashtbl.create 0
......
...@@ -74,6 +74,8 @@ let publish ~page ~name ~descr ~synopsis ?(details = []) () = ...@@ -74,6 +74,8 @@ let publish ~page ~name ~descr ~synopsis ?(details = []) () =
let _href = Doc.publish ~page ~name:id ~title ~index content [] in let _href = Doc.publish ~page ~name:id ~title ~index content [] in
atom dlink atom dlink
(* -------------------------------------------------------------------------- *)
let unit = atom @@ Markdown.plain "-" let unit = atom @@ Markdown.plain "-"
let any = atom @@ Markdown.emph "any" let any = atom @@ Markdown.emph "any"
let int = atom @@ Markdown.emph "int" let int = atom @@ Markdown.emph "int"
...@@ -101,30 +103,50 @@ let union ts = flow @@ Markdown.(glue ~sep:(plain "|") (List.map protect ts)) ...@@ -101,30 +103,50 @@ let union ts = flow @@ Markdown.(glue ~sep:(plain "|") (List.map protect ts))
let option t = atom @@ Markdown.(protect t @ code "?") let option t = atom @@ Markdown.(protect t @ code "?")
let field (a,t) = Markdown.( escaped a @ code ":" @ t.text ) (* -------------------------------------------------------------------------- *)
type tag = {
tag_name : string ;
tag_descr : Markdown.text ;
}
let tags ?(title="Tag") (tgs : tag list) =
let open Markdown in
let header = [
plain title, Left;
plain "Description", Left
] in
let row tg = [ escaped tg.tag_name ; tg.tag_descr ] in
Markdown.Table {
caption = None ; header ; content = List.map row tgs ;
}
(* -------------------------------------------------------------------------- *)
let mfield (a,t) = Markdown.( escaped a @ code ":" @ t.text )
let record fds = let record fds =
let fields = let fields =
if fds = [] then Markdown.plain "…" else if fds = [] then Markdown.plain "…" else
Markdown.(glue ~sep:(code ";") (List.map field fds)) Markdown.(glue ~sep:(code ";") (List.map mfield fds))
in atom @@ Markdown.(code "{" @ fields @ code "}") in atom @@ Markdown.(code "{" @ fields @ code "}")
type field = { type field = {
name : string ; fd_name : string ;
syntax : t ; fd_syntax : t ;
descr : Markdown.text ; fd_descr : Markdown.text ;
} }
let fields ~title (fds : field list) = let fields ?(title="Field") (fds : field list) =
let open Markdown in let open Markdown in
let header = [ let header = [
plain title, Left; plain title, Left;
plain "Format", Center; plain "Format", Center;
plain "Description", Left plain "Description", Left
] in ] in
let column f = [ code f.name ; f.syntax.text ; f.descr ] in let row f = [ code f.fd_name ; f.fd_syntax.text ; f.fd_descr ] in
Markdown.Table { Markdown.Table {
caption = None ; header ; content = List.map column fds ; caption = None ; header ; content = List.map row fds ;
} }
(* -------------------------------------------------------------------------- *) (* -------------------------------------------------------------------------- *)
...@@ -51,10 +51,18 @@ val option : t -> t ...@@ -51,10 +51,18 @@ val option : t -> t
val record : (string * t) list -> t val record : (string * t) list -> t
val data : string -> Markdown.href -> t val data : string -> Markdown.href -> t
type field = { name : string ; syntax : t ; descr : Markdown.text } type tag = { tag_name : string ; tag_descr : Markdown.text }
(** Builds a table with fields column named with [~title] (** Builds a table with tags description.
(shall be capitalized) *) The [~title] is applied to the tag name column
val fields : title:string -> field list -> Markdown.element (shall be capitalized, defaults to ["Tag"]). *)
val tags : ?title:string -> tag list -> Markdown.element
type field = { fd_name : string ; fd_syntax : t ; fd_descr : Markdown.text }
(** Builds a table with fields description.
The [~title] is applied to the field name column
(shall be capitalized, defaults to ["Field"]). *)
val fields : ?title:string -> field list -> Markdown.element
(* -------------------------------------------------------------------------- *) (* -------------------------------------------------------------------------- *)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment