-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathalgorithm.ml
116 lines (102 loc) · 3.4 KB
/
algorithm.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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
type symbol =
| Label of string
| Child of int
let show_symbol = function
| Label f -> f
| Child i -> string_of_int i
module Labelled = struct
type 'a t = {
value: 'a;
mutable hits: int;
mutable matches: bool;
}
end
module LabelledTree =
Tree.Make(Labelled)
exception TreeError of string
let instantiate =
let rec go : Ast.Tree.t -> LabelledTree.t = function
| Node (f, xs) ->
let xs = List.map go xs in
{ value = Node (f, xs); hits = 0; matches = false }
| Wildcard ->
raise (TreeError "Can't instantiate pattern!")
in go
let rtl tree =
let paths : symbol list list ref = ref [] in
let rec go (acc : symbol list) : Ast.Tree.t -> unit = function
| Node (f, []) ->
paths := List.rev (Label (f^"0") :: acc) :: !paths
| Node (f, xs) ->
List.iteri (fun i -> go (Child i :: Label (f^string_of_int (List.length xs)) :: acc)) xs
| Wildcard ->
paths := List.rev acc :: !paths
in
go [] tree;
!paths
let parse t =
Parser.start Lexer.tokenise (Lexing.from_string t)
let label : LabelledTree.t -> symbol = function
| { value = Node (f, xs); _ } -> Label (f ^ string_of_int List.(length xs))
| _ -> raise (TreeError "Tree must be root labelled!")
type 'a entry = {
node: LabelledTree.t;
state: 'a Trie.Node.t;
mutable visited: int;
}
module S = Stack
let arity : LabelledTree.t -> int = function
| { value = Node (_, xs); _ } -> List.length xs
| _ -> 0
let child i : LabelledTree.t -> LabelledTree.t = function
| { value = Node (_, xs); _ } -> List.nth xs i
| _ -> failwith "Must have an ith child!"
let go pattern subject =
let pattern = parse pattern in
let subject = instantiate (parse subject) in
let paths = rtl pattern in
let trie = Trie.create () in
List.iter (Trie.add trie) paths;
Trie.compute trie;
(* move on root label of subject tree *)
let first =
Trie.Node.follow trie.root (label subject)
in
let stack = Vector.create ~dummy:(Obj.magic 0) in
Vector.push stack { node = subject; state = first; visited = (-1) };
let tabulate state =
let outs = Trie.Node.outputs state in
let register out =
let out' = List.filter (function Label _ -> true | _ -> false) out in
let len = List.length out' in
let entry = Vector.get stack (Vector.length stack - len) in
entry.node.hits <- entry.node.hits + 1;
if (entry.node.hits = List.length paths) then
entry.node.matches <- true;
in
List.iter register outs
in
tabulate first;
while not (Vector.is_empty stack) do
let { node; state; visited } as top = Vector.top stack in
if visited = (arity node - 1) then
ignore (Vector.pop stack)
else begin
top.visited <- visited + 1;
let int_state = Trie.Node.follow state (Child top.visited) in
tabulate int_state;
let node' = child top.visited node in
let state' = Trie.Node.follow int_state (label node') in
Vector.push stack { node = node'; state = state'; visited = (-1) };
tabulate state'
end
done;
let rec show : LabelledTree.t -> string = function
| { value = Node (f, []); matches; _ } ->
Printf.sprintf (if matches then "[%s]" else "%s") f
| { value = Node (f, xs); matches; _ } ->
let xs = String.concat "," List.(map show xs) in
Printf.sprintf (if matches then "[%s(%s)]" else "%s(%s)") f xs
| _ -> ""
in
print_endline (show subject)