main graph.dats
  1#include "share/atspre_staload.hats"
  2#define ATS_DYNLOADFLAG 0
  3
  4staload "graph.sats"
  5staload "types.sats"
  6staload "parse.sats"
  7staload "libats/SATS/dynarray.sats"
  8staload _  = "libats/DATS/dynarray.dats"
  9staload "libats/SATS/hashtbl_linprb.sats"
 10staload _ = "libats/DATS/hashtbl_linprb.dats"
 11staload _ = "libats/DATS/hashfun.dats"
 12staload UN = "prelude/SATS/unsafe.sats"
 13
 14exception GraphErr of ()
 15
 16assume node_id   = usize
 17assume action_id = usize
 18
 19vtypedef thegraph = @{
 20    nodes = dynarray(node),
 21    actions = dynarray(action),
 22    paths = hashtbl(string, node_id)
 23}
 24
 25assume graph = thegraph
 26
 27implement mkgraph() =
 28    let 
 29        val n = dynarray_make_nil<node>           (i2sz (64))
 30        val a = dynarray_make_nil<action>         (i2sz (64))
 31        val p = hashtbl_make_nil<string, node_id> (i2sz(128))
 32    in
 33        @{nodes = n, actions = a, paths = p} 
 34    end
 35
 36fun node_free(n: node): void = 
 37    let 
 38        val @{path = p, producer = pr, consumers = c} = n
 39    in
 40        strptr_free(p);
 41        list_vt_free(c)
 42    end
 43
 44fun action_free(a: action): void = 
 45    let 
 46        val @{inp = i, out = o, rule = r, bindings = b } = a
 47    in
 48        list_vt_free(o);
 49        list_vt_free(i);
 50        strptr_free(r);
 51        bindings_free(b)
 52    end
 53
 54(* define how to destroy one element for array node *)
 55implement array_uninitize$clear<node>(i, node) =
 56   let 
 57       val () = node_free(node)
 58       (* mark as no longer containing anything*)
 59       prval () = topize(node)
 60   in () 
 61   end
 62 
 63(* for array action *)
 64implement array_uninitize$clear<action>(i, action) =
 65    let 
 66        val ()   = action_free(action)
 67        prval () = topize(action)
 68    in ()
 69    end
 70
 71implement graph_free(g) =
 72    let
 73        val @{nodes = n, actions = a, paths = p} = g
 74        var ncount: usize
 75        var acount: usize
 76        (* consume a dynarray and transfer into an arrayptr *)
 77        val nstorage = dynarray_getfree_arrayptr(n, ncount)
 78        val astorage = dynarray_getfree_arrayptr(a, acount)
 79    in 
 80        (* this calls array_uninitize$clear *)
 81        arrayptr_freelin<node>(nstorage, ncount);
 82        arrayptr_freelin<action>(astorage, acount); 
 83        hashtbl_free(p)
 84    end
 85
 86(* ideally we dont search + insert if absent (seeing as hashtbl_insert_opt returns the presence 
 87 * of the id again) it would be better to have 
 88 *
 89 * exists -> return id
 90 * doesent exist -> insert *)
 91(*if a node exists: return it, if it doesnet ,create it and return it*)
 92fun mknode(g: &graph, path: Strptr1): node_id = 
 93    let 
 94        (*XXX unsafe*)
 95        val found = hashtbl_search_opt<string, node_id>(g.paths, $UN.strptr2string(path)) 
 96    in
 97        case+ found of 
 98        | ~Some_vt(id) => ( (*the node exists*)
 99            strptr_free(path); (*free the path we're searching for *)
100            id (*return the node id*) )
101        | ~None_vt()   => ( (* the node doesnt exist *)
102            let val newid = dynarray_get_size(g.nodes) (*the id will be the size of the node array *)
103                val key   = $UN.strptr2string(path) (*borrow key before putting path in the new node*)
104                val newnode : node = @{path = path, producer = None(), consumers = nil_vt()} 
105                val ()    = dynarray_insert_atend_exn<node>(g.nodes, newnode) 
106                val prev  = hashtbl_insert_opt<string, node_id>(g.paths, key, newid) 
107            in  
108                case+ prev of
109                | ~None_vt(  ) => newid 
110                | ~Some_vt(id) => $raise GraphErr
111            end )
112    end
113
114(* call mknode on a list of paths *)
115fun intern_paths {n:nat} (g: &graph, paths: list_vt(Strptr1, n)): list_vt(node_id, n) =
116    case+ paths of
117    | ~nil_vt() => nil_vt() 
118    | ~cons_vt(path, rest) => 
119        let
120            val id  = mknode(g, path)
121            val ids = intern_paths(g, rest)
122            val all = cons_vt(id, ids)
123        in
124            all
125        end
126
127fun setprod(g: &graph, nid: node_id, aid: action_id): void = 
128    let 
129        var n: node = dynarray_takeout_at_exn<node>(g.nodes, nid) (*probably slow to takeout and reinsert*)
130        val hasprod = 
131            case+ n.producer of 
132            | None( ) => false
133            | Some(_) => true
134        val () = 
135            if hasprod then () else n.producer := Some(aid)
136        val () = dynarray_insert_at_exn<node>(g.nodes, nid, n)
137    in
138        if hasprod then $raise GraphErr else ()
139    end
140
141fun setcons(g: &graph, nid: node_id, aid: action_id): void = 
142    let 
143        var n: node = dynarray_takeout_at_exn<node>(g.nodes, nid) (*probably slow to takeout and reinsert*)
144        val ncs     = cons_vt(aid, n.consumers)
145        val ()      = n.consumers := ncs
146        val ()      = dynarray_insert_at_exn<node>(g.nodes, nid, n)
147    in
148        ()
149    end
150
151fun producers(g: &graph, ids: !List0_vt(node_id), aid: action_id): void = 
152    case+ ids of
153    | nil_vt() => ()
154    | @cons_vt(entry, rest) => (
155        setprod(g, entry, aid);
156        producers(g, rest, aid);
157        fold@(ids) )
158
159fun consumers(g: &graph, ids: !List0_vt(node_id), aid: action_id): void = 
160    case+ ids of
161    | nil_vt() => ()
162    | @cons_vt(entry, rest) => (
163        setcons(g, entry, aid);
164        consumers(g, rest, aid);
165        fold@(ids) )
166
167
168fun mkedge(g: &graph, e: edge): void = 
169    let
170        val @{output = o, rule = r, input = i, bindings = b} = e
171        val no        = intern_paths(g, o)
172        val ni        = intern_paths(g, i)
173        val nextid    = dynarray_get_size(g.actions)
174        val ()        = producers(g, no, nextid)
175        val ()        = consumers(g, ni, nextid)
176        val newaction : action = @{inp = ni, out = no, rule = r, bindings = b}
177        val ()        = dynarray_insert_atend_exn<action>(g.actions, newaction)
178    in
179        ()
180    end
181
182(* fun mkedges(g: &graph, edges: List0_vt(edge)): void = *)
183implement mkedges(g, edges) = 
184    case+ edges of 
185    | ~nil_vt() => () 
186    | ~cons_vt(edge, rest) => (
187        mkedge (g, edge);
188        mkedges(g, rest) )
189
190fun dotnodes(g: &graph, i: usize): void = 
191    if i < dynarray_get_size(g.nodes) then
192        let
193            val n  = dynarray_takeout_at_exn<node>(g.nodes, i)
194            val () = println!("  n", i, " [shape=box, label=\"", n.path, "\"];")
195            val () = dynarray_insert_at_exn<node>(g.nodes, i, n)
196        in
197            dotnodes(g, i + i2sz(1))
198        end
199    else ()
200
201fun inputarrows(nodes: !List0_vt(node_id), aid: action_id): void = 
202    case+ nodes of 
203    | nil_vt() => ()
204    | @cons_vt(nid, rest) => (
205        println!("  n", nid, " -> a", aid, ";");
206        inputarrows(rest, aid);
207        fold@(nodes) )
208
209fun outputarrows(nodes: !List0_vt(node_id), aid: action_id): void =
210    case+ nodes of
211    | nil_vt() => ()
212    | @cons_vt(nid, rest) => (
213        println!("  a", aid, " -> n", nid, ";");
214        outputarrows(rest, aid);
215        fold@(nodes) )
216
217fun dotactions(g: &graph, i: usize): void = 
218    if i < dynarray_get_size(g.actions) then
219        let 
220            val a  = dynarray_takeout_at_exn<action>(g.actions, i)
221            val () = println!("  a", i, "[shape=ellipse, label=\"", a.rule, "\"];");
222            val () = inputarrows (a.inp, i)
223            val () = outputarrows(a.out, i)
224            val () = dynarray_insert_at_exn<action>(g.actions, i, a)
225        in
226            dotactions(g, i + i2sz(1))
227        end
228     else()
229
230implement dot(g) = (
231    println!("digraph build {");
232    println!("  rankdir=LR;");
233    dotnodes(g, i2sz(0));
234    dotactions(g, i2sz(0));
235    println!("}") )
236