Skip to content

Commit eb2ca68

Browse files
committed
New files for spdiff-restructuring
The goal is to split the code into more (smaller) units instead of the current mess. Restructuring the code should in the end allow making a Spdiff module that can be used elsewhere.
1 parent 47ee898 commit eb2ca68

File tree

5 files changed

+204
-0
lines changed

5 files changed

+204
-0
lines changed

env.ml

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
open Gtree
2+
3+
let mk_env (m, t) = [(m, t)]
4+
5+
let empty_env = ([] : ((string * gtree) list))
6+
7+
(* given env and value t, find the _first_ binding m->t in env and return m
8+
* there may be other bindings in env such that m'->t
9+
*)
10+
let rev_lookup env t =
11+
let rec loop env = match env with
12+
| [] -> None
13+
| (m,t') :: env when t = t' -> Some m
14+
| _ :: env -> loop env
15+
in
16+
loop env
17+
18+
19+
(* replace subterms of t that are bound in env with the binding metavariable
20+
so subterm becomes m if m->subterm is in env
21+
assumes that if m1->st & m2->st then m1 = m2
22+
i.e. each metavariable denote DIFFERENT subterms
23+
so that one can uniquely perform the rev_lookup
24+
*)
25+
let rec rev_sub env t =
26+
match rev_lookup env t with
27+
| Some m -> mkA("meta", m)
28+
| None -> (match view t with
29+
| C(ty, ts) -> mkC(ty,
30+
List.rev (List.fold_left
31+
(fun acc_ts t -> rev_sub env t :: acc_ts)
32+
[] ts)
33+
)
34+
| _ -> t)
35+
36+
(* replace metavars in t with their corresponding binding in env (if any)
37+
*)
38+
let rec sub env t =
39+
if env = [] then t
40+
else
41+
let rec loop t' = match view t' with
42+
| C (ct, ts) ->
43+
mkC(ct, List.rev (
44+
List.fold_left (fun b a -> (loop a) :: b) [] ts
45+
))
46+
| A ("meta", mvar) -> (try
47+
List.assoc mvar env with Not_found ->
48+
mkA ("meta", mvar)
49+
)
50+
| _ -> t'
51+
in
52+
loop t
53+
54+
let rev_assoc a l =
55+
fst(List.find (function (m,b) -> b = a) l)

gtree_util.ml

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
open Gtree
2+
open Env
3+
4+
let metactx = ref 0
5+
let reset_meta () = metactx := 0
6+
let inc x = let v = !x in (x := v + 1; v)
7+
let ref_meta () = inc metactx
8+
let mkM () = mkA("meta", "X" ^ string_of_int(ref_meta()))
9+
let meta_name m = match view m with
10+
| A("meta", n) -> n
11+
| _ -> raise (failwith "trying to fetch metaname of non-meta value")
12+
13+
let make_gmeta name = mkA ("meta", name)
14+
15+
let new_meta env t =
16+
let m = "X" ^ string_of_int (ref_meta ()) in
17+
[make_gmeta m], [(m,t)]
18+
let is_meta v = match view v with | A("meta", _) -> true | _ -> false
19+
20+
let merge_terms t1 t2 =
21+
let rec loop env t1 t2 =
22+
if t1 == t2
23+
then (t1, env)
24+
else match view t1, view t2 with
25+
| C(ty1, ts1), C(ty2, ts2)
26+
when ty1 = ty2 && List.length ts1 = List.length ts2
27+
-> let ts1, env' = List.fold_left2
28+
(fun (acc_ts, env') t1' t2' ->
29+
let t'', env'' = loop env' t1' t2'
30+
in (t'' :: acc_ts, env'')
31+
)
32+
([],env) ts1 ts2
33+
in (mkC(ty1, List.rev ts1), env')
34+
| _ ->
35+
(match rev_lookup env (t1, t2) with
36+
| None -> let meta = mkM () in
37+
let metaName = meta_name meta in
38+
(meta, (metaName, (t1,t2)) :: env)
39+
| Some name -> (mkA ("meta", name), env)
40+
)
41+
in
42+
loop [] t1 t2
43+
44+

spdiff.mli

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module type Spdiff =
2+
sig
3+
type term
4+
type term_pattern
5+
type term_patch
6+
7+
type changeset
8+
9+
val get_term_patterns : changeset -> term_pattern list
10+
val get_term_patches : changeset -> term_patch list
11+
end
12+

spdiffimpl.ml

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
open Spdiff
2+
open Gtree
3+
4+
module SpdiffImpl : Spdiff =
5+
struct
6+
type term = gtree
7+
type term_pattern = gtree
8+
type term_patch = (term_pattern * term_pattern) list
9+
10+
type changeset = (term * term) list
11+
12+
module Term =
13+
struct
14+
open Hashcons
15+
type t = gtree
16+
let compare t1 t2 =
17+
if t1 == t2 then 0
18+
else if t1.hkey < t2.hkey then -1 else 1
19+
end
20+
21+
module TermSet = Set.Make(Term)
22+
23+
let get_subterms t =
24+
let rec loop acc subt = match view subt with
25+
| A _ -> TermSet.add subt acc
26+
| C(_, ts) -> List.fold_left loop (TermSet.add subt acc) ts in
27+
loop TermSet.empty t
28+
29+
(*
30+
* Given a changeset, find the set of term-patterns that occur in all of the
31+
* LHS terms.
32+
*
33+
* The näive approach:
34+
* compute all subterms for all LHS terms;
35+
* for each subterm, try to anti-unify with all subterms in other
36+
* term-pairs
37+
*)
38+
let get_term_patterns cset =
39+
let lhs_terms = List.rev_map fst cset in
40+
let lhs_subterm_sets = List.rev_map get_subterms lhs_terms in
41+
let g subterm acc_term_patterns =
42+
43+
in
44+
let f acc_term_patterns term_set =
45+
TermSet.fold g term_set acc_term_patterns
46+
in
47+
TermSet.elements (
48+
List.fold_left f TermSet.empty lhs_subterm_sets
49+
)
50+
51+
let get_term_patches cset = []
52+
end

util.ml

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
let grow
2+
stop_grow
3+
add_res
4+
ext_cur
5+
acc cur tail
6+
=
7+
let rec loop acc cur tail =
8+
match tail with
9+
| [] -> add_res cur acc
10+
| ls :: tail -> List.fold_left
11+
(fun acc y ->
12+
let ext = ext_cur y cur in
13+
if stop_grow ext acc
14+
then acc
15+
else loop acc ext tail
16+
)
17+
acc ls
18+
in
19+
loop acc cur tail
20+
21+
let all_seqs all_subterms =
22+
if List.length all_subterms = 1
23+
then List.map (fun x -> [x]) (List.hd all_subterms)
24+
else
25+
let stop ext acc = List.mem ext acc in
26+
let add_res cur acc = cur :: acc in
27+
let ext_cur elt cur = elt :: cur in
28+
let h, t = List.hd all_subterms, List.tl all_subterms in
29+
List.fold_left (fun acc x ->
30+
grow stop add_res ext_cur acc [x] t) [] h
31+
32+
let all_patterns all_subterm_seqs =
33+
if List.length all_subterm_seqs = 1
34+
then List.map (fun x -> [x]) (List.hd all_subterm_seqs)
35+
else
36+
let stop ext acc = List.mem ext acc in
37+
let add_res cur acc = cur :: acc in
38+
let ext_cur elt cur = elt :: cur in
39+
let h, t = List.hd all_subterm_seqs, List.tl all_subterm_seqs in
40+
List.fold_left (fun acc x ->
41+
grow stop add_res ext_cur acc [x] t) [] h

0 commit comments

Comments
 (0)