package fsml

  1. Overview
  2. Docs

Source file dot.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
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
(**********************************************************************)
(*                                                                    *)
(*              This file is part of the FSML library                 *)
(*                     github.com/jserot/fsml                         *)
(*                                                                    *)
(*  Copyright (c) 2020-present, Jocelyn SEROT.  All rights reserved.  *)
(*                                                                    *)
(*  This source code is licensed under the license found in the       *)
(*  LICENSE file in the root directory of this source tree.           *)
(*                                                                    *)
(**********************************************************************)

type options = {
    mutable node_shape: string;
    mutable node_style: string;
    mutable rankdir: string;
    mutable layout: string;
    mutable mindist: float
  }

let default_options = {
    node_shape = "circle";
    node_style = "solid";
    rankdir = "UD";
    layout = "dot"; 
    mindist = 1.0;
  }

let output oc ?(options=default_options) m = 
    let open Fsm in
    let ini_id = "_ini" in
    let dump_istate () = 
      Printf.fprintf oc "%s [shape=point; label=\"\"; style = invis]\n" ini_id in
    let string_of_output_valuation vs =
      Misc.string_of_list ~f:(function (n,v) -> "\\n" ^ n ^ "=" ^ Expr.to_string v) ~sep:"" vs in
    let dump_state (id,oval) =
      Printf.fprintf oc "%s [label = \"%s%s\", shape = %s, style = %s]\n"
        id
        id
        (string_of_output_valuation oval)
        options.node_shape
        options.node_style in
    let string_of_guards guards = 
      let ss = List.map Guard.to_string guards in
      let l = List.fold_left (fun m s -> max m (String.length s)) 0 ss in
      let s = Misc.string_of_list ~f:Fun.id ~sep:"\\n" ss in
      s, l in
    let string_of_actions actions = 
      let ss = List.map Action.to_string actions in
      let l = List.fold_left (fun m s -> max m (String.length s)) 0 ss in
      let s = Misc.string_of_list ~f:Fun.id ~sep:"\\n" ss in
      s, l in
    let dump_itransition (dst,actions) =
      let s, l  = string_of_actions actions in
      match s with
      | "" ->
         Printf.fprintf oc "%s->%s\n" ini_id dst
      | _ ->
         let sep = "\n" ^ String.make l '_' ^ "\n" in
         Printf.fprintf oc "%s->%s [label=\"%s%s\"]\n" ini_id dst sep s in
    let dump_transition (src,guards,actions,dst) =
      let s1, l1  = string_of_guards guards in
      let s2, l2  = string_of_actions actions in
      match s1, s2 with 
      | "", "" ->
         Printf.fprintf oc "%s->%s\n" src dst
      | _, "" ->
         Printf.fprintf oc "%s->%s [label=\"%s\"]\n" src dst s1
      | "", _ ->
         let sep = "\n" ^ String.make l2 '_' ^ "\n" in
         Printf.fprintf oc "%s->%s [label=\"%s%s\"]\n" src dst sep s2
      | _, _ ->
         let sep = "\n" ^ String.make (max l1 l2) '_' ^ "\n" in
         Printf.fprintf oc "%s->%s [label=\"%s%s%s\"]\n" src dst s1 sep s2 in
    Printf.fprintf oc "digraph %s {\nlayout = %s;\nrankdir = %s;\nsize = \"8.5,11\";\nlabel = \"\"\n center = 1;\n nodesep = \"0.350000\"\n ranksep = \"0.400000\"\n fontsize = 14;\nmindist=\"%1.1f\"\n"
      m.id
      options.layout
      options.rankdir
      options.mindist;
    dump_istate ();
    List.iter dump_state m.states;
    dump_itransition m.itrans;
    List.iter dump_transition m.trans;
    Printf.fprintf oc "}\n"

let write fname ?(options=default_options) m = 
  let oc = open_out fname in
  output oc ~options m;
  Printf.printf "Wrote file %s\n" fname;
  close_out oc
  
let view ?(options=default_options) ?(fname="") ?(cmd="open -a Graphviz") m = 
  let fname = match fname with
    | "" -> "/tmp/" ^ m.Fsm.id ^ "_fsm.dot"
    | _ -> fname in
  let _ = write fname ~options m in
  Sys.command (cmd ^ " " ^ fname)
OCaml

Innovation. Community. Security.