From a5a8d6f3713a799f018ee84917bb0894eeb6fed9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Loi=CC=88c=20Correnson?= <loic.correnson@cea.fr> Date: Tue, 23 Jun 2020 15:17:49 +0200 Subject: [PATCH] [ivette] typescript API --- ivette/.gitignore | 1 + ivette/Makefile | 16 ++++++ ivette/api/server_tsc.ml | 99 ++++++++++++++++++++++++++++++++++ src/plugins/server/package.ml | 23 +++++--- src/plugins/server/package.mli | 8 +-- 5 files changed, 136 insertions(+), 11 deletions(-) create mode 100644 ivette/api/server_tsc.ml diff --git a/ivette/.gitignore b/ivette/.gitignore index da037a9e2fa..481007d7156 100644 --- a/ivette/.gitignore +++ b/ivette/.gitignore @@ -4,6 +4,7 @@ .dome-*.stamp .dome-*.back +.server-tsc node_modules yarn.lock yarn-error.log diff --git a/ivette/Makefile b/ivette/Makefile index 37b317bdb83..99550aae931 100644 --- a/ivette/Makefile +++ b/ivette/Makefile @@ -30,6 +30,22 @@ fixlint: dome-pkg dome-templ tsc: typecheck fixlint +# -------------------------------------------------------------------------- +# --- Frama-C API +# -------------------------------------------------------------------------- + +.PHONY: api + +api: .server-tsc + +.server-tsc: ../bin/toplevel.byte api/server_tsc.ml + @echo "[Ivette] Generating TypeScript API" + ../bin/frama-c.byte -load-module api/server_tsc.ml -server-tsc + @touch $@ + +../bin/toplevel.byte: + make -C .. -kj byte + # -------------------------------------------------------------------------- # --- Ivette Documentation # -------------------------------------------------------------------------- diff --git a/ivette/api/server_tsc.ml b/ivette/api/server_tsc.ml new file mode 100644 index 00000000000..7108f00ffbb --- /dev/null +++ b/ivette/api/server_tsc.ml @@ -0,0 +1,99 @@ +(* -------------------------------------------------------------------------- *) +(* --- Frama-C TypeScript API Generator --- *) +(* -------------------------------------------------------------------------- *) + +module Self = Plugin.Register + (struct + let name = "Server TypeScript API" + let shortname = "server-tsc" + let help = "Generate TypeScript API for Server" + end) + +module TSC = Self.Action + (struct + let option_name = "-server-tsc" + let help = "Generate TypeScript API" + end) + +module OUT = Self.String + (struct + let option_name = "-server-tsc-out" + let arg_name = "dir" + let default = "api" + let help = "Output directory (default is './api')" + end) + +module Md = Markdown +module Pkg = Server.Package + +(* -------------------------------------------------------------------------- *) +(* --- TS Utils --- *) +(* -------------------------------------------------------------------------- *) + +let keywords = [ + "break"; "case"; "catch"; "class"; "const"; "continue"; "debugger"; + "default"; "delete"; "do"; "else"; "enum"; "export"; "extends"; "false"; + "finally"; "for"; "function"; "if"; "import"; "in"; "instanceof"; "new"; + "null"; "return"; "super"; "switch"; "this"; "throw"; "true"; "try"; + "typeof"; "var"; "void"; "while"; "with"; "as"; "implements"; "interface"; + "let"; "package"; "private"; "protected"; "public"; "static"; "yield"; "any"; + "boolean"; "constructor"; "declare"; "get"; "module"; "require"; "number"; + "set"; "string"; "symbol"; "type"; "from"; "of"; + "Json"; +] + +let pp_descr = Md.pp_text ?page:None + +(* -------------------------------------------------------------------------- *) +(* --- Main Generator --- *) +(* -------------------------------------------------------------------------- *) + +let makePackage pkg name fmt = + begin + let open Pkg in + Format.fprintf fmt "/* --- Generated Frama-C Server API --- */@\n" ; + Format.fprintf fmt "/**@\n%a@\n" pp_descr pkg.p_descr ; + Format.fprintf fmt " @@packageDocumentation@\n" ; + Format.fprintf fmt " @@module frama-c/%s@\n" name ; + Format.fprintf fmt "*/@\n" ; + let names = Pkg.resolve ~keywords pkg in + Format.fprintf fmt "import * as Json from 'dome/data/json'@\n" ; + Pkg.IdMap.iter + (fun id name -> + let pkg = Pkg.name_of_pkg ~sep:"/" id.plugin id.package in + if id.name = name then + Format.fprintf fmt "import { %s } from '%s';@\n" + name pkg + else + Format.fprintf fmt "import { %s: %s } from '%s';@\n" + id.name name pkg + ) names ; + List.iter + (fun d -> + Format.fprintf fmt "// Declare '%a'@\n" Pkg.pp_ident d.d_ident + ) pkg.p_content + end + +(* -------------------------------------------------------------------------- *) +(* --- Main Generator --- *) +(* -------------------------------------------------------------------------- *) + +let generate () = + begin + Pkg.iter + begin fun pkg -> + Self.feedback "Package %a" Pkg.pp_pkgname pkg ; + let name = Pkg.name_of_pkginfo ~sep:"/" pkg in + let file = Printf.sprintf "%s/%s.ts" (OUT.get ()) name in + let dir = Filename.dirname file in + Format.eprintf "DIR %S@." dir ; + if not (Sys.file_exists dir && Sys.is_directory dir) then + Extlib.mkdir ~parents:true dir 0o755 ; + Command.print_file file (makePackage pkg name) ; + end + end + + +let () = Db.Main.extend generate + +(* -------------------------------------------------------------------------- *) diff --git a/src/plugins/server/package.ml b/src/plugins/server/package.ml index 2c1fdf16826..982269288b2 100644 --- a/src/plugins/server/package.ml +++ b/src/plugins/server/package.ml @@ -44,7 +44,7 @@ let pp_plugin_step fmt = function let pp_ident fmt { plugin ; package ; name } = ( pp_plugin_step fmt plugin ; List.iter (pp_step fmt) package ; - Format.pp_print_string fmt name ) + pp_step fmt name ) (* -------------------------------------------------------------------------- *) (* --- Name Resolution --- *) @@ -232,15 +232,22 @@ type packageInfo = { p_content : declInfo list ; } -let name_of_ident id = - String.concat "." @@ match id.plugin with +let name_of_ident ?(sep=".") id = + String.concat sep @@ match id.plugin with | Kernel -> "kernel" :: id.package @ [ id.name ] | Plugin p -> p :: (id.package @ [id.name ]) -let name_of_pkginfo pkg = - String.concat "." @@ match pkg.p_plugin with - | Kernel -> "kernel" :: pkg.p_package - | Plugin p -> p :: pkg.p_package +let name_of_pkg ?(sep=".") plugin package = + String.concat sep @@ match plugin with + | Kernel -> "kernel" :: package + | Plugin p -> p :: package + +let name_of_pkginfo ?sep { p_plugin ; p_package } = + name_of_pkg ?sep p_plugin p_package + +let pp_pkgname fmt { p_plugin ; p_package } = + ( pp_plugin_step fmt p_plugin ; + List.iter (pp_step fmt) p_package ) (* -------------------------------------------------------------------------- *) (* --- Visitors --- *) @@ -293,7 +300,7 @@ type package = { mutable revDecl : declInfo list ; (* in reverse order *) } -let name_of_package pkg = name_of_pkginfo pkg.pkgInfo +let name_of_package ?sep pkg = name_of_pkginfo ?sep pkg.pkgInfo let registry = ref IdSet.empty (* including packages *) let packages = ref [] (* in reverse order *) diff --git a/src/plugins/server/package.mli b/src/plugins/server/package.mli index 58364ba3fee..dd0de862fba 100644 --- a/src/plugins/server/package.mli +++ b/src/plugins/server/package.mli @@ -97,6 +97,7 @@ type packageInfo = { (* -------------------------------------------------------------------------- *) val pp_plugin : Format.formatter -> plugin -> unit +val pp_pkgname : Format.formatter -> packageInfo -> unit val pp_ident : Format.formatter -> ident -> unit val pp_jtype : Format.formatter -> jtype -> unit @@ -185,9 +186,10 @@ val iter : (packageInfo -> unit) -> unit (** Assigns non-classing names for each identifier. *) val resolve : ?keywords: string list -> packageInfo -> string IdMap.t -val name_of_pkginfo : packageInfo -> string -val name_of_package : package -> string -val name_of_ident : ident -> string +val name_of_pkg : ?sep:string -> plugin -> string list -> string +val name_of_pkginfo : ?sep:string -> packageInfo -> string +val name_of_package : ?sep:string -> package -> string +val name_of_ident : ?sep:string -> ident -> string (* -------------------------------------------------------------------------- *) (* --- Markdown Generation --- *) -- GitLab