Skip to content
Snippets Groups Projects
kernel_ast.ml 6.54 KiB
Newer Older
(**************************************************************************)
(*                                                                        *)
(*  This file is part of Frama-C.                                         *)
(*                                                                        *)
(*  Copyright (C) 2007-2019                                               *)
(*    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 Cil_types
open Data
module Jutil = Yojson.Basic.Util

(* -------------------------------------------------------------------------- *)
(* --- Frama-C Ast Services                                               --- *)
(* -------------------------------------------------------------------------- *)

let page = Doc.page `Kernel ~title:"Ast Services" ~filename:"ast.md"

module ExecCompute = Request.Register(Junit)(Junit)
    (struct
      let kind = `EXEC
      let name = "Kernel.Ast.ExecCompute"
      let descr = Markdown.rm "Ensures that AST is computed"
      let page = page
      let details = []
      type input = unit
      type output = unit
      let process = Ast.compute
    end)

(* -------------------------------------------------------------------------- *)
(* ---  Printers                                                          --- *)
(* -------------------------------------------------------------------------- *)

module Tag =
struct

  open Printer_tag

  type index = (string,localizable) Hashtbl.t

  let kid = ref 0

  let index () = Hashtbl.create 0

  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 of_stmt s = Printf.sprintf "#s%d" s.sid
  let of_start s = Printf.sprintf "#k%d" s.sid
  let of_varinfo v = Printf.sprintf "#v%d" v.vid

  let create_tag = function
    | PStmt(_,st) -> of_stmt st
    | PStmtStart(_,st) -> of_start st
    | PVDecl(_,_,vi) -> of_varinfo vi
    | PLval _ -> Printf.sprintf "#l%d" (incr kid ; !kid)
    | PExp _ -> Printf.sprintf "#e%d" (incr kid ; !kid)
    | 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 create item =
    let tag = create_tag item in
    let index = STATE.get () in
    Hashtbl.add index tag item ; tag

  let lookup = Hashtbl.find (STATE.get())

end

module PP = Printer_tag.Make(Tag)

(* -------------------------------------------------------------------------- *)
(* --- Ast Data                                                           --- *)
(* -------------------------------------------------------------------------- *)

module Stmt = Data.Collection
    (struct
      type t = stmt
      let syntax = Syntax.publish ~page ~name:"stmt"
          ~synopsis:Syntax.ident
          ~descr:(Markdown.praw "Code statement identifier")
      let to_json st = `String (Tag.of_stmt st)
      let of_json js =
        try
          let open Printer_tag in
          match Tag.lookup (Jutil.to_string js) with
          | PStmt(_,st) -> st
          | _ -> raise Not_found
        with Not_found ->
          Data.failure "Unknown stmt id" js
    end)

module Ki = Data.Collection
    (struct
      type t = kinstr
      let syntax = Syntax.union [ Syntax.tag "global" ; Stmt.syntax ]
      let to_json = function
        | Kglobal -> `String "global"
        | Kstmt st -> `String (Tag.of_stmt st)
      let of_json = function
        | `String "global" -> Kglobal
        | js -> Kstmt (Stmt.of_json js)
    end)

module Kf = Data.Collection
    (struct
      type t = kernel_function
      let syntax = Syntax.publish ~page ~name:"function"
          ~synopsis:Syntax.ident
          ~descr:(Markdown.praw "Function, identified by its global name.")
      let to_json kf = `String (Kernel_function.get_name kf)
      let of_json js =
        try Jutil.to_string js |> Globals.Functions.find_by_name
        with Not_found -> Data.failure "Undefined function" js
    end)

(* -------------------------------------------------------------------------- *)
(* --- Functions                                                          --- *)
(* -------------------------------------------------------------------------- *)

module GetFunctions = Request.Register(Junit)(Kf.Jlist)
    (struct
      let kind = `GET
      let name = "Kernel.Ast.GetFunctions"
      let descr = Markdown.rm "Collect all functions in the AST"
      let page = page
      let details = []
      type input = unit
      type output = kernel_function list
      let process () =
        let pool = ref [] in
        Globals.Functions.iter (fun kf -> pool := kf :: !pool) ;
        List.rev !pool
    end)

module PrintFunction = Request.Register(Kf)(Jtext)
    (struct
      let kind = `GET
      let name = "Kernel.Ast.PrintFunction"
      let descr = Markdown.rm "Print the AST of a function"
      let page = page
      let details = []
      type input = kernel_function
      type output = json
      let process kf =
        Jbuffer.to_json PP.pp_global (Kernel_function.get_global kf)
    end)

(* -------------------------------------------------------------------------- *)