-
Notifications
You must be signed in to change notification settings - Fork 6
/
diff.ml
3940 lines (3567 loc) · 122 KB
/
diff.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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
(*
* Copyright 2005-2009, Ecole des Mines de Nantes, University of Copenhagen
* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller, Jesper Andersen
* This file is part of Coccinelle.
*
* Coccinelle is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, according to version 2 of the License.
*
* Coccinelle 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Coccinelle. If not, see <http://www.gnu.org/licenses/>.
*
* The authors reserve the right to distribute this or future versions of
* Coccinelle under other licenses.
*)
let debug = false
let debug_msg x = if debug then print_endline x else ()
let fdebug_string f x = if f then print_string x else ()
let fdebug_endline f x = if f then print_endline x else ()
let debug_newline () = if debug then print_newline () else ()
exception Fail of string
exception Impossible of int
open Hashcons
open Gtree
open Gtree_util
open Env
open Difftype
type term = gtree
type up = term diff
type node = gtree
type edge = Control_flow_c2.edge
type gflow = (node, edge) Ograph_extended.ograph_mutable
exception Merge3
module GT =
struct
type t = gtree
let compare = Pervasives.compare
end
module DiffT =
struct
(*type t = (((string,string) gtree) diff) list*)
type t = gtree diff
let compare = Pervasives.compare
end
let pfold fold_f l opid concat =
List.fold_left (fun acc ls -> concat (fold_f ls acc) acc) opid l
(*
*module DiffT =
* struct
* type t = ((string,string) gtree) diff
* let compare = Pervasives.compare
* end
*
*)
(* user definable references here ! *)
(* copy from main.ml initialized in main-function *)
let patterns = ref false
let verbose = ref false
(* use new and fancy malign algo to decide subpatch relation *)
let malign_mode = ref false
(* terms are only abstracted until we reach this depth in the term *)
let abs_depth = ref 0
(* only allow abstraction of subterms of terms that are smaller than this number
*)
let abs_subterms = ref 0
(* the FV of rhs should be equal to lhs -- thus lhs can not drop metavars under
* strict mode
*)
let be_strict = ref false
(* allow the same term to be abstracted by different metavariables
*)
let use_mvars = ref false
(* should we really use the fixed information to prevent terms from getting
* abstracted
*)
let be_fixed = ref false
(* not used atm: should have indicated the number of allow exceptions as to how
* often a patch should be found
*)
let no_exceptions = ref 0
let no_occurs = ref 0
(* should we allow non-matching parts to be safe?
*)
let relax = ref false
(* copy of the main.ml var with the same name; initialized in main.ml *)
let do_dmine = ref false
(* copy from main.ml; initialized in main.ml *)
let nesting_depth = ref 0
(* have we not already initialized the table of abstracted terms *)
let not_counted = ref true
(* should the type of expressions be printed inline ? *)
let inline_type_print = ref false
let v_print s = if !verbose then (print_string s; flush stdout)
let v_print_string = v_print
let v_print_endline s = if !verbose then print_endline s
let v_print_newline () = v_print_endline ""
(* non-duplicating cons *)
let (+++) x xs = if List.mem x xs then xs else x :: xs
(* convenience for application *)
let (+>) o f = f o
(* sublist *)
let sublist l1 l2 = l1 +> List.for_all (function e -> List.mem e l2)
(* equality of lists *)
let eq_lists l1 l2 = sublist l1 l2 && sublist l2 l1
let skip = mkA("SKIP","...")
(* check that list l1 is a sublist of l2 *)
let subset_list l1 l2 =
List.for_all (function e1 -> (List.mem e1 l2)) l1
let string_of_meta p = match view p with
(*| A ("meta", m) -> "$" ^ m*)
| A ("meta", m) -> m
| A (_, b) -> b
| C _ -> raise (Fail "not meta")
let not_compound gt = match view gt with
| C("comp{}", _) | A("comp{}", _)
| C("onedecl", _)
| C("onedecl_ini", _) -> false
| _ -> true
let non_phony p = match view p with
| A("phony", _)
| C("phony", _) -> false
(*
| A(_, "N/H")
| A(_, "N/A") -> false
| A(head,_)
| C(head,_) -> not(is_header head)
*)
| _ -> true
let is_assignment a_string = match a_string with
| "assign="
| "assign+="
| "assign-="
| "assign*="
| "assign%="
| "assign/="
| "assign&="
| "assign|="
| "assignx="
| "assign?=?" -> true
| _ -> false
let extract_aop a_string = match a_string with
| "assign=" -> "="
| "assign+=" -> "+="
| "assign-=" -> "-="
| "assign*=" -> "*="
| "assign%=" -> "%="
| "assign/=" -> "/="
| "assign&=" -> "&="
| "assign|=" -> "|="
| "assignx=" -> "^="
| "assign?=?" -> "?=?"
| _ -> raise (Fail "Not assign operator?")
let rec string_of_gtree str_of_t str_of_c gt =
let rec string_of_itype itype = (match view itype with
| A("itype", c) -> "char"
| C("itype", [sgn;base]) ->
(match view sgn, view base with
| A ("sgn", "signed") , A (_, b) -> "signed " ^ string_of_meta base
| A ("sgn", "unsigned"), A (_, b) -> "unsigned " ^ string_of_meta base
| A ("meta", _), A(_, b) -> b
| _ -> raise (Fail "string_of_itype inner")
)
| _ -> raise (Fail "string_of_itype outer")
)
and string_of_param param =
match view param with
| C("param", [reg;name;ft]) ->
let r = match view reg with
| A("reg",r) -> r
| A("meta",x0) -> string_of_meta reg
| _ -> raise (Fail "string_of_param reg") in
let n = match view name with
| A("ident", n) -> n
| A("meta", x0) -> string_of_meta name
| _ -> raise (Fail "string_of_param name") in
r ^ " " ^ string_of_ftype [ft] ^ " " ^ n
| _ -> loop param
and string_of_ftype fts =
let loc cvct = match view cvct with
| A("tqual","const") -> "const"
| A("tqual","vola") -> "volatile"
| A("btype","void") -> "void"
| C("btype", [{node=C("itype", _)} as c]) -> string_of_itype c
| C("btype", [{node=A("itype", _)} as a]) -> string_of_itype a
| C("btype", [{node=A("ftype", ft)}]) -> ft
| C("pointer", [ft]) -> string_of_ftype [ft] ^ " * "
| C("array", [cexpopt; ft]) ->
string_of_ftype [ft] ^ " " ^
(match view cexpopt with
| A("constExp", "none") -> "[]"
| C("constExp", [e]) -> "[" ^ loop e ^ "]"
| A("meta", x0) -> string_of_meta cexpopt
| _ -> raise (Fail "fail:array")
)
| C("funtype", rt :: pars) ->
let ret_type_string = string_of_ftype [rt] in
let par_type_strings = List.map string_of_param pars in
"("^ String.concat ", " par_type_strings
^ ")->" ^ ret_type_string
| C("enum", [{node=A ("enum_name", en)}; enumgt]) -> "enumTODO"
| C("struct", [{node=C(sname, [stype])}]) ->
"struct " ^ sname ^ "{" ^ loop stype ^"}"
| A ("struct", name) -> "struct " ^ name
| C ("typeName", [{node=A("meta",id)}; {node=A("fullType","unknown")}])
| C ("typeName", [{node=A("ident",id)}; {node=A("fullType","unknown")}]) -> id
| C ("typeName", [{node=A("ident",id)}; ft])
| C ("typeName", [{node=A("meta",id)}; ft]) -> string_of_ftype [ft] ^ " " ^ id
| _ -> loop cvct
(* | C(tp,ts) -> tp ^ "<" ^ String.concat ", " (List.map loop ts) ^ ">" *)
(* | A(tp,t) -> tp ^ ":" ^ t ^ ":" *)
in
String.concat " " (List.map loc fts)
and string_of_aop aop = match view aop with
| A("aop", op_str) -> op_str
| A("meta", x) -> x
| _ -> raise (Impossible 1017)
and none_exprstmt es = match view es with
| C("stmt", [e]) when none_exprstmt e -> true
| A("exprstmt", "none") -> true
| _ -> false
and loop gt = match view gt with
| A ("meta", c) -> string_of_meta gt
(* | A ("itype", _) -> string_of_itype gt
| A (t,c) -> t ^ ":" ^ c *)
| C ("cast", [totype; exp]) -> "(" ^ loop totype ^ ")" ^ loop exp
| C ("if", [c;b1;b2]) ->
"if(" ^ loop c ^") " ^ loop b1 ^
(if none_exprstmt b2
then ""
else " else " ^ loop b2)
| C ("binary_arith", [aop;e1;e2]) ->
let aop_str = string_of_aop aop in
let e1_str = loop e1 in
let e2_str = loop e2 in
e1_str ^ " " ^ aop_str ^ " " ^ e2_str
| C ("fulltype", ti) -> string_of_ftype ti
| C ("const", [{node=A(_, c)}]) -> c
| C ("itype", _ ) -> string_of_itype gt
| C ("exp", [e]) -> loop e
(*| C ("exp", [{node=A("meta", x0)}; e]) -> "(" ^ loop e ^ ":_)"*)
| C ("exp", [{node=C ("TYPEDEXP", [t])} ; e]) ->
if !inline_type_print
then
"(" ^ loop e ^ ":" ^ loop t ^ ")"
else
loop e
| C ("call", f :: args) ->
loop f ^ "(" ^ String.concat "," (List.map loop args) ^ ")"
| C ("binary_logi", [{node=A("logiop", op_str)}; e1;e2]) ->
loop e1 ^ op_str ^ loop e2
| C ("record_ptr", [e;f]) ->
loop e ^ "->" ^ loop f
| C ("record_acc", [e;f]) ->
loop e ^ "." ^ loop f
| C ("array_acc", [e1;e2]) ->
loop e1 ^ "[" ^ loop e2 ^ "]"
| C ("stmt", [st]) when not_compound st ->
loop st ^ ";"
| C ("exprstmt", [gt]) -> loop gt
| C (assignment, [l;r]) when is_assignment assignment ->
loop l ^ extract_aop assignment ^ loop r
| C ("&ref", [gt]) -> "&" ^ loop gt
| C ("dlist", ds) ->
ds
+> List.map loop
+> String.concat ", "
| C ("onedecl", [v;ft;sto]) ->
loop ft ^ " " ^ loop v(* storage and inline ignored *)
| C ("onedecl_ini", [var_gt; ini_exp; ftype; stor]) ->
loop ftype ^ " "
^ loop var_gt ^ " = "
^ loop ini_exp
| C ("ini", [e]) -> loop e
| C ("stmt", [s]) -> loop s ^ ";"
| C ("return", [e]) -> "return " ^ loop e
| A ("goto", lab) -> "goto " ^ lab
| C ("comp{}", compound) ->
"{" ^
compound +> List.map loop +> String.concat " "
^ "}"
| C ("def", [{node=A("fname", n)}; {node=C("funtype", rt :: args)}; body])
| C ("def", [{node=A("meta", n)}; {node=C("funtype", rt :: args)}; body]) ->
string_of_ftype [rt] ^ " " ^ n ^ " (" ^
List.map string_of_param args +> String.concat ", "
^ ") " ^
loop body
| C ("cond3", [cond_gt;t_gt;f_gt]) ->
loop cond_gt ^ " ? " ^
loop t_gt ^ " : " ^
loop f_gt
| C ("argtype", [at]) ->loop at
| C ("macroargs", args) ->
"(" ^ args +> List.map loop +> String.concat "," ^ ")"
| C ("param", ps) -> string_of_param gt
| C ("iniList", inis) ->
"{" ^ inis +> List.map loop
+> String.concat ","
^ "}"
| C (t, gtrees) ->
str_of_t t ^ "[" ^
String.concat "," (List.map loop gtrees)
^ "]"
| A (t,c) -> c
(* | A (t,c) -> str_of_t t ^ "<" ^ str_of_c c ^ ">" *)
in
loop gt
let verbose_string_of_gtree gt =
let rec loop gt = match view gt with
(*
| A(t,c) -> t ^ "⟨" ^ c ^ "⟩"
| C (t, gtrees) ->
t ^ "⟦" ^
String.concat "," (List.map loop gtrees)
^ "⟧"
*)
| A(t,c) -> t ^ "(" ^ c ^ ")"
| C (t, gtrees) ->
t ^ "[" ^
String.concat "," (List.map loop gtrees)
^ "]"
in loop gt
let str_of_ctype x = x
let str_of_catom a = a
let string_of_gtree' gt =
if !verbose
then
verbose_string_of_gtree gt
else
string_of_gtree str_of_ctype str_of_catom gt
let collect_metas gt =
let gs gt = match view gt with
| A("meta",x) -> x ^ ";"
| _ -> raise (Fail "fail:collect_metas gs") in
let (!!) gt = match view gt with
| A("meta", _) -> true | _ -> false in
let gtype gt = string_of_gtree' gt in
let rec loop acc_metas gt =
if !!gt then (gs gt) +++ acc_metas
else match view gt with
| A _ -> acc_metas
| C("const", [gt]) when !! gt -> ("const " ^ gs gt) +++ acc_metas
| C("call", fargs) ->
fargs +> List.fold_left (fun acc_metas gt ->
match view gt with
| _ when !! gt -> ("expression " ^ gs gt) +++ acc_metas
| _ -> loop acc_metas gt
) acc_metas
| C("exp",[gt']) when !!gt' -> ("expression " ^ gs gt') +++ acc_metas
| C ("exp", [{node=C ("TYPEDEXP", [t])} ; e])
when !!e -> (gtype t ^ " " ^ gs e) +++ acc_metas
| C ("record_acc", [e;f]) ->
let acc = if !! f
then ("identifier " ^ gs f) +++ acc_metas
else loop acc_metas f in
if !! e
then ("expression " ^ gs e) +++ acc
else loop acc e
| C ("record_ptr", [e;f]) ->
let acc = if !! f
then ("identifier " ^ gs f) +++ acc_metas
else loop acc_metas f in
if !! e
then ("expression " ^ gs e) +++ acc
else loop acc e
| C (_, gts) -> gts +> List.fold_left
(fun acc_meta gt ->
loop acc_meta gt
) acc_metas
in
loop [] gt
let rec string_of_diff d =
let make_string_header gt = collect_metas gt in
match d with
| SEQ(p1,p2) -> "SEQ: " ^ string_of_diff p1 ^ " ; " ^ string_of_diff p2
| UP(s,s') ->
"@@\n" ^ String.concat "\n" (make_string_header s) ^
"\n@@\n" ^
"- " ^ (string_of_gtree' s) ^
"\n" ^
"+ " ^ (string_of_gtree' s')
| ADD s -> "ADD: " ^ string_of_gtree' s
| ID s -> "ID: " ^ string_of_gtree' s
| RM s -> "RM: " ^ string_of_gtree' s
| PENDING_ID s -> "PID: " ^ string_of_gtree' s
| PENDING_RM s -> "PRM: " ^ string_of_gtree' s
let print_diffs ds =
print_endline "{{{";
List.iter (fun d -> print_endline (string_of_diff d)) ds;
print_endline "}}}"
let extract_pat p = match view p with
| C("CM", [p]) -> p
| _ -> raise (Match_failure (string_of_gtree' p, 772,0))
let rec string_of_spdiff d =
let make_string_header gt = collect_metas gt in
match d with
| SEQ(p1,p2) -> "SEQ: " ^ string_of_spdiff p1 ^ " ; " ^ string_of_spdiff p2
| ID s when s == skip -> " ..."
| ID s -> " " ^ extract_pat s +> string_of_gtree'
| UP(s,s') -> "@@\n" ^ String.concat "\n" (make_string_header s) ^
"\n@@\n" ^
"- " ^ (string_of_gtree' s) ^ "\n" ^
"+ " ^ (string_of_gtree' s')
| ADD s -> "+ " ^ s +> string_of_gtree'
| RM s -> "- " ^ extract_pat s +> string_of_gtree'
| _ -> failwith "Unhandled string_of_spdiff"
let string_of_spdiff_header sp =
let meta_vars = List.fold_left
(fun acc_meta d ->
match d with
| ID s
| RM s
| ADD s -> List.fold_left
(fun acc_ms meta -> meta +++ acc_ms)
acc_meta
(collect_metas s)
| _ -> acc_meta
) [] sp
in
"@@\n" ^ String.concat "\n" meta_vars ^ "\n" ^
"@@"
let string_of_spdiff_full sp =
string_of_spdiff_header sp ^ "\n" ^
String.concat "\n" (List.map string_of_spdiff sp)
(* a solution is a list of updates, diff list and the idea is that it will
* transform an original gt into the updated gt' *)
let print_sol sol =
print_endline "[[";
List.iter (function dg ->
print_endline (string_of_diff dg);
print_endline "\t++"
) sol;
print_endline "]]"
let print_sols solutions =
(*List.iter print_sol solutions*)
print_sol solutions
let explode st =
let rec loop i acc =
if i = 0
then acc
else
let i' = i-1 in
loop i' (st.[i'] :: acc) in
List.map Char.escaped (loop (String.length st) [])
let spacesep st =
Str.split (Str.regexp "[ ]+") st
let subset lhs rhs =
List.for_all (function e -> List.mem e rhs) lhs
let lcs src tgt =
let slen = List.length src in
let tlen = List.length tgt in
let m = Array.make_matrix (slen + 1) (tlen + 1) 0 in
Array.iteri (fun i jarr -> Array.iteri (fun j e ->
let i = if i = 0 then 1 else i in
let j = if j = 0 then 1 else j in
let s = List.nth src (i - 1) in
let t = List.nth tgt (j - 1) in
if s = t
then
m.(i).(j) <- (try m.(i-1).(j-1) + 1 with _ -> 1)
else
let a = try m.(i).(j-1) with _ -> 0 in
let b = try m.(i-1).(j) with _ -> 0 in
m.(i).(j) <- max a b
) jarr) m;
m
let rm_dub ls =
(*List.rev *)
(List.fold_left
(fun acc e -> if List.mem e acc then acc else e :: acc)
[] ls)
let max3 a b c = max a (max b c)
let lcs_shared size_f src tgt =
let slen = List.length src in
let tlen = List.length tgt in
let m = Array.make_matrix (slen + 1) (tlen + 1) 0 in
Array.iteri
(fun i jarr -> Array.iteri
(fun j e ->
(* make sure we stay within the boundaries of the matrix *)
let i = if i = 0 then 1 else i in
let j = if j = 0 then 1 else j in
(* get the values we need to compare in s and t *)
let s = List.nth src (i - 1) in
let t = List.nth tgt (j - 1) in
(* now see how much of s and t is shared *)
let size = size_f s t in
let c = (try m.(i-1).(j-1) + size with _ -> size) in (* update/equal *)
let a = try m.(i).(j-1) with _ -> 0 in (* adding is better *)
let b = try m.(i-1).(j) with _ -> 0 in (* removing is better *)
m.(i).(j) <- max3 a b c
) jarr) m;
m
let extract_base_name orig_s =
try
let idx = String.index orig_s '@' in
String.sub orig_s 0 idx
with Not_found -> orig_s
let rec shared_gtree t1 t2 =
let (+=) a b = if a = b then 1 else 0 in
let rec comp l1 l2 =
match l1, l2 with
| [], _ | _, [] -> 0
(* below: only do shallow comparison *)
(*| x :: xs, y :: ys -> localeq x y + comp xs ys in*)
| x :: xs, y :: ys -> shared_gtree x y + comp xs ys in
match view t1, view t2 with
| A ("ident", name1), A ("ident", name2) ->
if extract_base_name name1
= extract_base_name name2
then 0
else 1
| A (ct1, at1), A (ct2, at2) ->
(ct1 += ct2) + (at1 += at2)
| C(ct1, ts1), C(ct2, ts2) ->
(ct1 += ct2) + comp ts1 ts2
| _, _ -> 0
let rec get_diff_old src tgt =
match src, tgt with
| [], _ -> List.map (function e -> ADD e) tgt
| _, [] -> List.map (function e -> RM e) src
| _, _ ->
let m = lcs_shared shared_gtree src tgt in
let slen = List.length src in
let tlen = List.length tgt in
let rec loop i j =
let i' = if i > 0 then i else 1 in
let j' = if j > 0 then j else 1 in
let s = List.nth src (i' - 1) in
let t = List.nth tgt (j' - 1) in
if i > 0 && j > 0 && (shared_gtree s t > 0)
then
let up = if s = t then ID s else UP(s,t) in
loop (i - 1) (j - 1) @ [up]
else if j > 0 && (i = 0 || m.(i).(j - 1) >= m.(i - 1).(j))
then
loop i (j - 1) @ [ADD (List.nth tgt (j - 1))]
else if
i > 0 && (j = 0 || m.(i).(j - 1) < m.(i - 1).(j))
then
loop (i - 1) j @ [RM (List.nth src (i - 1))]
else (assert(i=j && j=0) ;
[]) (* here we should have that i = j = 0*)
in loop slen tlen
let rec get_diff src tgt =
match src, tgt with
| [], _ -> List.map (function e -> ADD e) tgt
| _, [] -> List.map (function e -> RM e) src
| _, _ ->
let m = lcs_shared shared_gtree src tgt in
let slen = List.length src in
let tlen = List.length tgt in
let rec loop i j =
if i > 0 && j = 0
then
loop (i - 1) j @ [RM (List.nth src (i - 1))]
else if j > 0 && i = 0
then
loop i (j - 1) @ [ADD (List.nth tgt (j - 1))]
else if i > 0 && j > 0
then
let s = List.nth src (i - 1) in
let t = List.nth tgt (j - 1) in
let score = m.(i).(j) in
let score_diag = m.(i-1).(j-1) in
let score_up = m.(i).(j-1) in
let score_left = m.(i-1).(j) in
if score = score_diag + (shared_gtree s t)
then
let up = if s = t then ID s else UP(s,t) in
loop (i - 1) (j - 1) @ [up]
else if score = score_left
then
loop (i - 1) j @ [RM (List.nth src (i - 1))]
else if score = score_up
then
loop i (j - 1) @ [ADD (List.nth tgt (j - 1))]
else raise (Fail "?????")
else
(assert(i=j && j = 0); [])
in loop slen tlen
(* normalize diff rearranges a diff so that there are no consequtive
* removals/additions if possible.
*)
let normalize_diff diff =
let rec get_next_add prefix diff =
match diff with
| [] -> None, prefix
| ADD t :: diff -> Some (ADD t), prefix @ diff
| t :: diff -> get_next_add (prefix @ [t]) diff
in
let rec loop diff =
match diff with
| [] -> []
| RM t :: diff' ->
let add, tail = get_next_add [] diff' in
(match add with
| None -> RM t :: loop tail
| Some add -> RM t :: add :: loop tail)
| UP(t,t') :: diff -> RM t :: ADD t' :: loop diff
| i :: diff' -> i :: loop diff' in
loop diff
(* correlate_diff tries to take sequences of -+ and put them in either
UP(-,+) or ID. Notice, that permutations of arguments is not
detected and not really supported in the current framework either
*)
(* sub_list p d takes a list d and returns the prefix-list of d of elements all
* satisfying p and the rest of the list d
*)
let sub_list p d =
let rec loop d =
match d with
| [] -> [], []
| x :: xs ->
if p x
then
let nxs, oxs = loop xs in
x :: nxs, oxs
else [], x :: xs
in
loop d
let rec correlate rm_list add_list =
match rm_list, add_list with
| [], [] -> []
| [], al -> al
| rl, [] -> rl
| RM r :: rl, ADD a :: al ->
let u = if r = a then ID a else UP(r,a)
in
u :: correlate rl al
| _ -> raise (Fail "correleate")
(* the list of diffs returned is not in the same order as the input list
*)
let correlate_diffs d =
let rec loop d =
match d with
| [] -> [], []
| RM a :: d ->
let rm_list, d = sub_list
(function x -> match x with
| RM _ -> true
| _ -> false) ((RM a) :: d) in
let add_list, d = sub_list
(function x -> match x with
| ADD _ -> true
| _ -> false) d in
let ups' = correlate rm_list add_list in
let ups, d' = loop d in
ups' @ ups , d'
| x :: d -> match loop d with up, d' -> up, x :: d' in
let rec fix_loop (ups, d_old) d =
let ups_new, d_new = loop d in
if d_new = d_old
then ups_new @ ups, d_new
else fix_loop (ups_new @ ups, d_new) d_new
in
let n, o = fix_loop ([], []) d in
n @ o
let correlate_diffs_new ds =
if !Jconfig.verbose
then begin
print_endline "[Diff] correlate new called on : ";
ds +> List.map string_of_diff +> List.iter print_endline;
end;
let rec next_adds acc ds =
match ds with
| [] -> acc
| ADD d :: ds -> next_adds (d :: acc) ds
| RM _ :: ds
| UP _ :: ds -> next_adds acc ds
| _ -> acc in
let rec loop acc_ds prefix suffix =
match suffix with
| [] -> acc_ds
| RM a :: suffix ->
let suffix_adds = next_adds [] suffix in
let pre_suf_adds = next_adds suffix_adds prefix in
if pre_suf_adds = []
then acc_ds
else pre_suf_adds +> List.fold_left
(fun acc_ds add ->
UP(a, add) :: acc_ds) acc_ds
| up :: suffix -> loop (up :: acc_ds) (up :: prefix) suffix in
loop [] [] ds
exception Nomatch
(* Take an env and new binding for m = t; if m is already bound to t then we
* return the same env, and else we insert it in front The key point is that we
* get an exception when we try to bind a variable to a NEW value!
*)
let merge_update env (m, t) =
try
let v = List.assoc m env in
if v = t
then env
else raise Nomatch
with Not_found -> (m,t) :: env
(* take two environments; for each binding of m that is in both env1 and env2,
* the binding must be equal; for variables that are in only one env, we simply
* add it
*)
let merge_envs env1 env2 =
List.fold_left (fun env (m,t) -> merge_update env (m,t)) env2 env1
(* try to see if a term st matches another term t
*)
let rec match_term st t =
match view st, view t with
| C("head:def", [defp]), C("head:def", [deft]) ->
match_term defp deft
| A("meta",mvar), _ -> mk_env (mvar, t)
| A(sct,sat), A(ct,at) when sct = ct && sat = at -> empty_env
(* notice that the below lists s :: sts and t :: ts will always match due to
* the way things are translated into gtrees. a C(type,args) must always have
* at least ONE argument in args
*)
| C("def", [namep;paramsp;bodyp]), C("def", [name;params;body]) ->
match_term namep name +> merge_envs (match_term paramsp params)
| C(sct,s :: sts), C(ct, t :: ts)
when sct = ct && List.length sts = List.length ts ->
List.rev (
List.fold_left2 (fun acc_env st t ->
merge_envs (match_term st t) acc_env
) (match_term s t) sts ts)
| _ -> raise Nomatch
let is_read_only t = match view t with
| C("RO", [t']) -> true
| _ -> false
let get_read_only_val t = match view t with
| C("RO", [t']) -> t'
| _ -> raise Nomatch
let mark_as_read_only t = mkC("RO", [t])
let can_match p t =
try (match match_term p t with | _ -> true)
with
| Nomatch -> false
| _ -> raise (Impossible 191)
(*
* occursht is a hashtable indexed by a pair of a pattern and term
* the idea is that each (p,t) maps to a boolean which gives the result of
* previous computations of "occurs p t"; if no previous result exists, one is
* computed
*)
module PatternTerm = struct
type t = gtree * gtree
let equal (p1,t1) (p2,t2) =
p1 == p2 && t1 == t2
let hash (p,t) = abs (19 * (19 * p.hkey + t.hkey) + 2)
end
module Term = struct
type t = gtree
let equal t t' = t == t'
let hash t = t.hkey
end
module TT = Hashtbl.Make(Term)
module PT = Hashtbl.Make(PatternTerm)
(* hashtable for counting patterns *)
let count_ht = TT.create 591
let prepruned_ht = TT.create 591
(* let occursht = PT.create 591 *)
let find_match pat t =
let cm = can_match pat in
let rec loop t =
cm t || match view t with
| A _ -> false
| C(ct, ts) -> List.exists (fun t' -> loop t') ts
in
loop t
(*
try
if
PT.find occursht (pat,t)
then true
else (
print_endline ("pattern: " ^ string_of_gtree' pat);
print_endline ("not occurring in ");
print_endline ("term: " ^ string_of_gtree' t);
print_newline ();
false)
with Not_found ->
let res = loop t in
(PT.add occursht (pat,t) res;
res)
*)
let is_header head_str =
head_str.[0] = 'h' &&
head_str.[1] = 'e' &&
head_str.[2] = 'a' &&
head_str.[3] = 'd'
let control_else = mkA("control:else", "Else")
let control_true = mkA("control:true", "True")
let control_inloop = mkA("control:loop", "InLoop")
let is_control_node n =
n = control_else
|| n = control_true
|| n = control_inloop
let is_head_node n =
n = control_else ||
n = control_inloop ||
match view n with
| C("head:def", _) -> false
| A(hd,_ ) | C(hd, _ ) -> is_header hd
let find_nested_matches pat t =
let mt t = try Some (match_term pat t) with Nomatch -> None in
let rec loop depth acc_envs t =
if depth = 0
then acc_envs
else
let acc_envs' = (match mt t with
| Some e -> e :: acc_envs
| None -> acc_envs) in
match view t with
| A _ -> acc_envs'
| C(_, ts) -> let l = loop (depth - 1) in
List.fold_left l acc_envs' ts
in
(* loop !nesting_depth [] t *)
if non_phony t
then loop !nesting_depth [] t
else []
let can_match_nested pat t =
match find_nested_matches pat t with
| [] -> false
| _ -> true
let return_and_bind (up,t) (t',env) = (
t',env
)
let get_unique ls =
let rec loop acc ls = match ls with
| [] -> acc
| e :: ls when List.mem e ls -> loop (e :: acc) ls
| _ :: ls -> loop acc ls in
let dupl = loop [] ls in
List.filter (function e -> not(List.mem e dupl)) ls
let get_common_unique ls1 ls2 =
let uniq1 = get_unique ls1 in
get_unique ls2
+> List.filter (function u2 -> List.mem u2 uniq1)
let patience_ref nums =
let get_rev_index ls = List.length ls in
let lookup_rev i ls = List.length ls - i +> List.nth ls in
let insert left e ls = match left with
| None -> (None, e) :: ls
| Some (stack) -> (Some (get_rev_index stack), e) :: ls in
let (<) n n' = n < (snd n') in
let (>>) stacks n =
let rec loop left stacks n =
match stacks with
| [] -> [insert left n []]
| (n' :: stack) :: stacks when n < n' -> (insert left n (n' :: stack)) :: stacks
| stack :: stacks -> stack :: (loop (Some stack) stacks n)
in loop None stacks n
in
let stacks = List.fold_left (>>) [] nums in
(* get the lcs *)
let rec lcs acc_lcs id remaining_stacks =
match remaining_stacks with
| [] -> acc_lcs
| stack :: stacks ->
let (nid_opt, e) = lookup_rev id stack in
(match nid_opt with
| None -> e :: acc_lcs
| Some nid -> lcs (e :: acc_lcs) nid stacks)
in
match List.rev stacks with
| [] -> []
| [(_, e) :: stack] -> [e]
| ((Some nid, e) :: _) :: stacks -> lcs [e] nid stacks
| _ -> raise (Fail "lcs stacks")
let get_slices lcs_orig ls_orig =
let take_until e ls =
let rec loop acc ls = match ls with
| [] -> (
let lcs_str = List.map string_of_gtree' lcs_orig +> String.concat " " in
let ls_str = List.map string_of_gtree' ls_orig +> String.concat " " in
print_endline "Exception";
print_endline ("lcs: " ^ lcs_str);
print_endline ("ls_str: " ^ ls_str);
raise (Fail "get_slices:take_until "))
| e' :: ls when e = e' -> List.rev acc, ls
| e' :: ls -> loop (e' :: acc) ls
in loop [] ls
in
let rec loop lcs ls =
match lcs with
| [] -> [ls]
| e :: lcs -> let slice, ls = take_until e ls in
slice :: loop lcs ls
in loop lcs_orig ls_orig
let rec patience_diff ls1 ls2 =
(* find the index of the given unique term t in ls *)
let get_uniq_index ls t =
let rec loop ls n = match ls with
| [] -> raise (Fail "not found get_uniq_index")
| t' :: ls when t = t' -> n
| _ :: ls -> loop ls (n + 1)
in
loop ls 0 in