Newer
Older

Loïc Correnson
committed
(**************************************************************************)
(* *)
(* This file is part of Frama-C. *)
(* *)

Loïc Correnson
committed
(* CEA (Commissariat à l'énergie atomique et aux énergies *)
(* alternatives) *)
(* *)
(* you can redistribute it and/or modify it under the terms of the GNU *)
(* Lesser General Public License as published by the Free Software *)
(* Foundation, version 2.1. *)
(* *)
(* It is distributed in the hope that it will be useful, *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *)
(* GNU Lesser General Public License for more details. *)
(* *)
(* See the GNU Lesser General Public License version 2.1 *)
(* for more details (enclosed in the file licenses/LGPLv2.1). *)
(* *)
(**************************************************************************)
open Data
module Md = Markdown
module Js = Yojson.Basic.Util

Loïc Correnson
committed
let package = Pkg.package ~title:"Ast Services" ~name:"ast" ~readme:"ast.md" ()

Loïc Correnson
committed
(* -------------------------------------------------------------------------- *)

Loïc Correnson
committed
(* -------------------------------------------------------------------------- *)
let () = Request.register ~package
~kind:`EXEC ~name:"compute"
~descr:(Md.plain "Ensures that AST is computed")
~input:(module Junit) ~output:(module Junit) Ast.compute

Loïc Correnson
committed
(* -------------------------------------------------------------------------- *)
(* --- Printers --- *)
(* -------------------------------------------------------------------------- *)
(* The kind of a marker. *)
module MarkerKind = struct
David Bühler
committed
let kind name =
Enum.tag
~name
~descr:(Md.plain (String.capitalize_ascii name))
kinds
let expr = kind "expression"
let lval = kind "lvalue"
let decl = kind "declaration"
let stmt = kind "statement"
let glob = kind "global"
let term = kind "term"
let prop = kind "property"
David Bühler
committed
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
let () =
Enum.set_lookup
kinds
(fun localizable ->
let open Printer_tag in
match localizable with
| PStmt _ -> stmt
| PStmtStart _ -> stmt
| PVDecl _ -> decl
| PLval _ -> lval
| PExp _ -> expr
| PTermLval _ -> term
| PGlobal _ -> glob
| PIP _ -> prop)
let data =
Request.dictionary
~package
~name:"markerKind"
~descr:(Md.plain "Marker kind")
kinds
include (val data : S with type t = Printer_tag.localizable)
end
module MarkerVar = struct
let vars = Enum.dictionary ()
let kind name =
Enum.tag
~name
~descr:(Md.plain (String.capitalize_ascii name))
vars
let none = kind "none"
let var = kind "variable"
let fct = kind "function"
let () =
Enum.set_lookup
vars
(fun localizable ->
let open Printer_tag in
match localizable with
| PLval (_, _, (Var vi, NoOffset))
| PVDecl (_, _, vi)
| PGlobal (GVar (vi, _, _) | GVarDecl (vi, _)) ->
if Cil.isFunctionType vi.vtype then fct else var
| PGlobal (GFun _ | GFunDecl _) -> fct
| PLval _ | PStmt _ | PStmtStart _
| PExp _ | PTermLval _ | PGlobal _ | PIP _ -> none)
let data =
Request.dictionary
~package
~name:"markerVar"
~descr:(Md.plain "Marker variable")
vars
David Bühler
committed
include (val data : S with type t = Printer_tag.localizable)
end

Loïc Correnson
committed
struct
open Printer_tag
type index = {
tags : string Localizable.Hashtbl.t ;
locs : (string,localizable) Hashtbl.t ;
}

Loïc Correnson
committed
let kid = ref 0
let index () = {
tags = Localizable.Hashtbl.create 0 ;
locs = Hashtbl.create 0 ;
}

Loïc Correnson
committed
module TYPE : Datatype.S with type t = index =
Datatype.Make
(struct
type t = index
include Datatype.Undefined
let reprs = [index()]
let name = "Server.Jprinter.Index"
let mem_project = Datatype.never_any_project
end)
module STATE = State_builder.Ref(TYPE)
(struct
let name = "Server.Jprinter.State"
let dependencies = []
let default = index
end)
let iter f =
Localizable.Hashtbl.iter (fun key str -> f (key, str)) (STATE.get ()).tags
let array =
let model = States.model () in
let () =
David Bühler
committed
~name:"kind"
~descr:(Md.plain "Marker kind")
~data:(module MarkerKind)
~get:fst
model
in
let () =
States.column
~name:"var"
~descr:(Md.plain "Marker variable")
~data:(module MarkerVar)
~get:fst
David Bühler
committed
in
~descr:(Md.plain "Marker short name")
~get:(fun (tag, _) -> Printer_tag.label tag)
~name:"descr"
~descr:(Md.plain "Marker declaration or description")
~data:(module Jstring)
~get:(fun (tag, _) -> Rich_text.to_string Printer_tag.pretty tag)
in
States.register_array
~package
~name:"markerInfo"
~descr:(Md.plain "Marker informations")

Loïc Correnson
committed
let create_tag = function
| PStmt(_,s) -> Printf.sprintf "#s%d" s.sid
| PStmtStart(_,s) -> Printf.sprintf "#k%d" s.sid
| PVDecl(_,_,v) -> Printf.sprintf "#v%d" v.vid

Loïc Correnson
committed
| PLval _ -> Printf.sprintf "#l%d" (incr kid ; !kid)
| PExp(_,_,e) -> Printf.sprintf "#e%d" e.eid

Loïc Correnson
committed
| PTermLval _ -> Printf.sprintf "#t%d" (incr kid ; !kid)
| PGlobal _ -> Printf.sprintf "#g%d" (incr kid ; !kid)
| PIP _ -> Printf.sprintf "#p%d" (incr kid ; !kid)
let { tags ; locs } = STATE.get () in
try Localizable.Hashtbl.find tags loc
with Not_found ->
let tag = create_tag loc in
Localizable.Hashtbl.add tags loc tag ;
Hashtbl.add locs tag loc ;
States.update array (loc, tag);
let lookup tag = Hashtbl.find (STATE.get()).locs tag
let markers = ref []
let jmarker kd =
let jt = Pkg.Jkey kd in markers := jt :: !markers ; jt
let jstmt = jmarker "stmt"
let jdecl = jmarker "decl"
let jlval = jmarker "lval"
let jexpr = jmarker "expr"
let jterm = jmarker "term"
let jglobal = jmarker "global"
let jproperty = jmarker "property"
let jtype = Data.declare ~package ~name:"marker"
~descr:(Md.plain "Localizable AST markers")
Pkg.(Junion (List.rev !markers))

Loïc Correnson
committed
let to_json loc = `String (create loc)
let of_json js =
try lookup (Js.to_string js)
with Not_found -> Data.failure "not a localizable marker"

Loïc Correnson
committed
end
module Printer = Printer_tag.Make(Marker)

Loïc Correnson
committed
(* -------------------------------------------------------------------------- *)
(* --- Ast Data --- *)
(* -------------------------------------------------------------------------- *)
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
module Stmt =
struct
type t = stmt
let jtype = Marker.jstmt
let to_json st =
let kf = Kernel_function.find_englobing_kf st in
Marker.to_json (PStmt(kf,st))
let of_json js =
let open Printer_tag in
match Marker.of_json js with
| PStmt(_,st) | PStmtStart(_,st) -> st
| _ -> Data.failure "not a stmt marker"
end
module Ki =
struct
type t = kinstr
let jtype = Pkg.Joption Marker.jstmt
let to_json = function
| Kglobal -> `Null
| Kstmt st -> Stmt.to_json st
let of_json = function
| `Null -> Kglobal
| js -> Kstmt (Stmt.of_json js)
end
module Kf =
struct
type t = kernel_function
let jtype = Pkg.Jkey "fct"
let to_json kf =
`String (Kernel_function.get_name kf)
let of_json js =
let key = Js.to_string js in
try Globals.Functions.find_by_name key
with Not_found -> Data.failure "Undefined function '%s'" key
end

Loïc Correnson
committed
(* -------------------------------------------------------------------------- *)
(* --- Functions --- *)
(* -------------------------------------------------------------------------- *)
let () = Request.register ~package
~kind:`GET ~name:"getFunctions"
~descr:(Md.plain "Collect all functions in the AST")
~input:(module Junit) ~output:(module Jlist(Kf))
begin fun () ->
let pool = ref [] in
Globals.Functions.iter (fun kf -> pool := kf :: !pool) ;
List.rev !pool
end
let () = Request.register ~package
~kind:`GET ~name:"printFunction"
~descr:(Md.plain "Print the AST of a function")
~input:(module Kf) ~output:(module Jtext)
(fun kf -> Jbuffer.to_json Printer.pp_global (Kernel_function.get_global kf))

Loïc Correnson
committed
module Functions =
struct
let key kf = Printf.sprintf "kf#%d" (Kernel_function.get_id kf)
let signature kf =
let global = Kernel_function.get_global kf in
Rich_text.to_string Printer_tag.pretty (PGlobal global)
let array : kernel_function States.array =
begin
let model = States.model () in
~name:"name"
~descr:(Md.plain "Name")
~data:(module Data.Jalpha)
~get:Kernel_function.get_name ;
States.column model
~name:"signature"
~descr:(Md.plain "Signature")
~data:(module Data.Jstring)
~get:signature ;
States.register_array model
~package ~key
~name:"functions"
~descr:(Md.plain "AST Functions")
~iter:Globals.Functions.iter
(* -------------------------------------------------------------------------- *)
(* --- Information --- *)
(* -------------------------------------------------------------------------- *)
module Info = struct
open Printer_tag
let print_function fmt name =
let stag = Transitioning.Format.stag_of_string name in
Transitioning.Format.pp_open_stag fmt stag;
Format.pp_print_string fmt name;
Transitioning.Format.pp_close_stag fmt ()
let print_kf fmt kf = print_function fmt (Kernel_function.get_name kf)
let print_variable fmt vi =
Format.fprintf fmt "Variable %s has type %a.@."
vi.vname Printer.pp_typ vi.vtype;
let kf = Kernel_function.find_defining_kf vi in
let pp_kf fmt kf = Format.fprintf fmt " of function %a" print_kf kf in
Format.fprintf fmt "It is a %s variable%a.@."
(if vi.vglob then "global" else if vi.vformal then "formal" else "local")
(Transitioning.Format.pp_print_option pp_kf) kf;
if vi.vtemp then
Format.fprintf fmt "This is a temporary variable%s.@."
(match vi.vdescr with None -> "" | Some descr -> " for " ^ descr);
Format.fprintf fmt "It is %sreferenced and its address is %staken."
(if vi.vreferenced then "" else "not ")
(if vi.vaddrof then "" else "not ")
let print_varinfo fmt vi =
if Cil.isFunctionType vi.vtype
then
Format.fprintf fmt "%a is a C function of type '%a'."
print_function vi.vname Printer.pp_typ vi.vtype
else print_variable fmt vi
let print_lvalue fmt _loc = function
| Var vi, NoOffset -> print_varinfo fmt vi
| lval ->
Format.fprintf fmt "This is an lvalue of type %a."
Printer.pp_typ (Cil.typeOfLval lval)
let print_localizable fmt = function
| PExp (_, _, e) ->
Format.fprintf fmt "This is a pure C expression of type %a."
Printer.pp_typ (Cil.typeOf e)
| PLval (_, _, lval) as loc -> print_lvalue fmt loc lval
| PVDecl (_, _, vi) ->
Format.fprintf fmt "This is the declaration of variable %a.@.@."
Printer.pp_varinfo vi;
print_varinfo fmt vi
| PStmt (kf, _) | PStmtStart (kf, _) ->
Format.fprintf fmt "This is a statement of function %a." print_kf kf
| _ -> ()
let get_marker_info loc =
let buffer = Jbuffer.create () in
let fmt = Jbuffer.formatter buffer in
print_localizable fmt loc;
Format.pp_print_flush fmt ();
Jbuffer.contents buffer
end
let () = Request.register ~package
~kind:`GET ~name:"getInfo"
~descr:(Md.plain "Get textual information about a marker")
~input:(module Marker) ~output:(module Jtext)
Info.get_marker_info
(* -------------------------------------------------------------------------- *)
(* --- Files --- *)
(* -------------------------------------------------------------------------- *)
let get_files () =
let files = Kernel.Files.get () in
List.map (fun f -> (f:Filepath.Normalized.t:>string)) files
let () =
Request.register
~descr:(Md.plain "Get the currently analyzed source file names")
~kind:`GET
~name:"getFiles"
~input:(module Junit) ~output:(module Jlist(Jstring))
get_files
let set_files files =
let s = String.concat "," files in
Kernel.Files.As_string.set s
let () =
Request.register
~descr:(Md.plain "Set the source file names to analyze.")
~kind:`SET
~name:"setFiles"
~input:(module Jlist(Jstring))
~output:(module Junit)
(* -------------------------------------------------------------------------- *)