This module contains additional definitions and lemmas on strings,
 including a total order relation. 
Require Import Orders.
Require Import Ascii.
Require Import List.
Require Import String.
Require Import Arith.
Require Import Min.
Require Import Equivalence.
Require Import EquivDec.
Require Import Compare_dec.
Require Import Lia.
Require Import LibUtilsCoqLibAdd.
 Total order on characters 
Module AsciiOrder <: 
OrderedTypeFull with Definition t:=
ascii.
  
Definition t:= 
ascii.
  
Definition eq := @
eq t.
  
Definition eq_equiv : (
Equivalence eq) := 
eq_equivalence.
  
Definition eq_dec := 
ascii_dec.
  
Definition compare (
a b:
ascii) : 
comparison :=
    
Nat.compare (
nat_of_ascii a) (
nat_of_ascii b).
  
Definition lt (
a b:
ascii) := 
compare a b = 
Lt.
  
Lemma lt_strorder : 
StrictOrder lt.
  Proof.
  Lemma lt_compat : 
Proper (
eq ==> 
eq ==> 
iff) 
lt.
  Proof.
  Lemma compare_eq_iff a b: 
compare a b = 
Eq <-> 
a = 
b.
  Proof.
  Lemma compare_spec :
    
forall x y : 
t, 
CompareSpec (
eq x y) (
lt x y) (
lt y x) (
compare x y).
  Proof.
  Lemma trichotemy a b : {
lt a b} + {
eq a b} + {
lt b a}.
  Proof.
    generalize (
compare_spec a b); 
intros nc.
    
destruct (
compare a b);
      [
left; 
right|
left;
left|
right]; 
inversion nc; 
trivial.
  Defined.
 
  Definition le (
a b:
ascii) :=
    
match compare a b with
    | 
Lt => 
True
    | 
Eq => 
True
    | 
Gt => 
False
    end.
  
Lemma le_lteq : 
forall x y : 
t, 
le x y <-> 
lt x y \/ 
eq x y.
  Proof.
    intros.
    
generalize (
compare_spec x y); 
inversion 1;
      
unfold le, 
lt, 
eq in *;
      
case_eq (
compare x y); 
intuition congruence.
  Qed.
 
  Lemma compare_refl_eq a: 
compare a a = 
Eq.
  Proof.
End AsciiOrder.
 Total order on strings 
Module StringOrder <: 
OrderedTypeFull with Definition t:=
string.
  
Definition t:= 
string.
  
Definition eq := @
eq t.
  
Definition eq_equiv : (
Equivalence eq) := 
eq_equivalence.
  
Definition eq_dec := 
string_dec.
  
Fixpoint compare (
a:
string) (
b:
string) : 
comparison :=
    
match a, 
b with
    | 
EmptyString, 
EmptyString => 
Eq
    | 
EmptyString, 
String _ _ => 
Lt
    | 
String _ _, 
EmptyString => 
Gt
    | 
String a' 
a'
s, 
String b' 
b'
s => 
      
match AsciiOrder.compare a' 
b' 
with
      | 
Lt => 
Lt
      | 
Eq => 
compare a'
s b'
s
      | 
Gt => 
Gt
      end
    end.
  
Definition lt (
a b:
string) := 
compare a b = 
Lt.
  
Lemma compare_spec :
    
forall x y : 
t, 
CompareSpec (
eq x y) (
lt x y) (
lt y x) (
compare x y).
  Proof.
  Lemma trichotemy a b : {
lt a b} + {
eq a b} + {
lt b a}.
  Proof.
    generalize (
compare_spec a b); 
intros nc.
    
destruct (
compare a b);
      [
left; 
right|
left;
left|
right]; 
inversion nc; 
trivial.
  Defined.
 
  Lemma compare_refl_eq a: 
compare a a = 
Eq.
  Proof.
  Lemma compare_eq_iff a b: 
compare a b = 
Eq <-> 
a = 
b.
  Proof.
  Instance lt_strorder : 
StrictOrder lt.
  Proof.
  Lemma lt_compat : 
Proper (
eq ==> 
eq ==> 
iff) 
lt.
  Proof.
  Program Definition lt_dec (
a b:
string) : {
lt a b} + {~
lt a b}
    := 
match compare a b with
       | 
Lt => 
left _
       | 
Eq => 
right _
       | 
Gt => 
right _
       end.
  Next Obligation.
    generalize (
compare_spec a b); 
rewrite <- 
Heq_anonymous; 
inversion 1.
    
trivial.
  Qed.
 
  Next Obligation.
  Next Obligation.
    generalize (
compare_spec a b); 
rewrite <- 
Heq_anonymous; 
inversion 1.
    
intro l2. 
apply (
asymmetry H0 l2).
  Qed.
 
  Definition le (
a b:
string) :=
    
match compare a b with
    | 
Lt => 
True
    | 
Eq => 
True
    | 
Gt => 
False
    end.
  
Lemma le_lteq : 
forall x y : 
t, 
le x y <-> 
lt x y \/ 
eq x y.
  Proof.
    intros.
    
generalize (
compare_spec x y); 
inversion 1;
      
unfold le, 
lt, 
eq in *;
      
case_eq (
compare x y); 
intuition congruence.
  Qed.
 
  Program Definition le_dec (
a b:
string) : {
le a b} + {~
le a b}
    := 
match compare a b with
       | 
Lt => 
left _
       | 
Eq => 
left _
       | 
Gt => 
right _
       end.
  Next Obligation.
    generalize (
compare_spec a b); 
rewrite <- 
Heq_anonymous; 
inversion 1.
    
apply le_lteq.
    
intuition.
  Qed.
 
  Next Obligation.
    generalize (
compare_spec a b); 
rewrite <- 
Heq_anonymous; 
inversion 1.
    
apply le_lteq.
    
intuition.
  Qed.
 
  Next Obligation.
End StringOrder.
 String prefixes 
Section Prefix.
  
Lemma substring_zero s :
    
substring 0 0 
s = ""%
string.
  Proof.
    induction s; reflexivity.
  Qed.
  
  Lemma substring_S a m s :
    
substring 0 (
S m) (
String a s) = 
String a (
substring 0 
m s).
  Proof.
    reflexivity.
  Qed.
  Lemma append_string_distr a s1 s2 :
    (
String a s1 ++ 
s2 = 
String a (
s1 ++ 
s2))%
string.
  Proof.
    auto.
  Qed.
  Lemma append_eq_inv1 x y z : 
append x y = 
append x z -> 
y = 
z.
  Proof.
    revert y z.
    induction x; simpl; trivial; intros.
    inversion H; subst.
    auto.
  Qed.
  Lemma prefix_refl y : 
prefix y y = 
true.
  Proof.
    induction y; simpl; trivial.
    match_destr; congruence.
  Qed.
  
  Lemma substring_append_cancel x y :
    
substring (
String.length x) (
String.length y) (
append x y) = 
y.
  Proof.
  Lemma string_length_append x y :
    
String.length (
append x y) = 
String.length x + 
String.length y.
  Proof.
    revert y.
    induction x; simpl; auto.
  Qed.
  Lemma prefix_nil post : 
prefix ""%
string post = 
true.
  Proof.
    destruct post; trivial.
  Qed.
  Lemma prefix_app pre post : 
prefix pre (
append pre post) = 
true.
  Proof.
    revert post.
    
induction pre; 
intros; 
simpl.
    - 
apply prefix_nil.
    - 
match_destr; 
intuition.
  Qed.
 
  Lemma prefix_break {
pre x} :
    
prefix pre x = 
true ->
    {
y | 
x = 
append pre y}.
  Proof.
    revert x.
    induction pre; simpl.
    - eauto.
    - destruct x; simpl; try discriminate.
      match_destr.
      subst; intros p.
      destruct (IHpre _ p).
      subst.
      eauto.
  Qed.
  
  Lemma substring_split s n m l :
    
append (
substring s n l) (
substring (
s+
n) 
m l) = 
substring s (
n+
m) 
l.
  Proof.
    revert n m s.
    induction l; simpl; destruct s; destruct n; simpl; trivial.
    - f_equal.
      apply IHl.
    - rewrite IHl; simpl; trivial.
    - rewrite IHl. simpl; trivial.
  Qed.
  Lemma substring_all l :
    
substring 0 (
String.length l) 
l = 
l.
  Proof.
    induction l; simpl; congruence.
  Qed.
  Lemma substring_bounded s n l :
    
substring s n l = 
substring s (
min n (
String.length l - 
s)) 
l.
  Proof.
    revert s n.
    induction l; destruct s; destruct n; simpl; trivial.
    - rewrite IHl; simpl.
      f_equal.
      f_equal.
      f_equal.
      lia.
    - rewrite IHl.
      match_case.
  Qed.
  Lemma substring_le_prefix s n m l :
    
n <= 
m ->
    
prefix (
substring s n l) (
substring s m l) = 
true.
  Proof.
    revert s n m.
    induction l; destruct s; destruct n; destruct m; simpl; trivial;
      try lia; intuition.
    match_destr; intuition.
  Qed.
  Lemma substring_prefix n l :
    
prefix (
substring 0 
n l) 
l = 
true.
  Proof.
  Lemma in_of_append pre y l :
    
In (
append pre y) 
l <->
    
In y (
map
            (
fun x => 
substring (
String.length pre) (
String.length x - 
String.length pre) 
x)
            (
filter (
prefix pre) 
l)).
  Proof.
  
  Lemma append_ass s1 s2 s3 : ((
s1 ++ 
s2) ++ 
s3 = 
s1 ++ 
s2 ++ 
s3)%
string.
  Proof.
    revert s2 s3.
    induction s1; simpl.
    - trivial.
    - intros. rewrite IHs1; trivial.
  Qed.
End Prefix.
 Character map over strings 
Section MapString.
  
Fixpoint map_string (
f:
ascii->
ascii) (
s:
string)
    := 
match s with
       | 
EmptyString => 
EmptyString
       | 
String a s' => 
String (
f a) (
map_string f s')
       
end.
  
Fixpoint flat_map_string (
f:
ascii->
string) (
s:
string)
    := 
match s with
       | 
EmptyString => 
EmptyString
       | 
String a s' => 
append (
f a) (
flat_map_string f s')
       
end.
  
Global Instance ascii_dec : 
EqDec ascii eq
    := 
ascii_dec.
End MapString.
Support for 'like' on strings 
Section Join.
  
Definition map_concat {
A} 
separator (
f:
A -> 
string) (
elems:
list A) : 
string :=
    
match elems with
    | 
nil => ""
    | 
e :: 
elems' =>
      (
fold_left (
fun acc e => 
acc ++ 
separator ++ (
f e)) 
elems' (
f e))%
string
    end.
  
End Join.
 Conversion between lists of characters and strings 
Section AsciiToString.
  
Fixpoint string_reverse_helper (
s:
string) (
acc:
string)
    := 
match s with
       | 
EmptyString => 
acc
       | 
String x xs => 
string_reverse_helper xs (
String x acc)
       
end.
  
Definition string_reverse (
s:
string) := 
string_reverse_helper s EmptyString.
  
Fixpoint string_to_list (
s:
string) : 
list ascii
    := 
match s with
       | 
EmptyString => 
nil
       | 
String x xs => 
cons x (
string_to_list xs)
       
end.
  
Fixpoint list_to_string (
l:
list ascii) : 
string
    := 
match l with
       | 
nil => 
EmptyString
       | 
cons x xs => 
String x (
list_to_string xs)
       
end.
  
  
Lemma string_to_list_to_string (
s:
string) :
    
list_to_string (
string_to_list s) = 
s.
  Proof.
    induction s; simpl; intuition congruence.
  Qed.
  Lemma list_to_string_to_list (
l:
list ascii) :
    
string_to_list (
list_to_string l) = 
l.
  Proof.
    induction l; simpl; intuition congruence.
  Qed.
  Lemma string_to_list_inj (
x y:
string) : 
    
string_to_list x = 
string_to_list y -> 
x = 
y.
  Proof.
  Lemma list_to_string_inj (
x y:
list ascii) : 
    
list_to_string x = 
list_to_string y -> 
x = 
y.
  Proof.
  Lemma string_reverse_helper_reverse_append s acc:
    
string_reverse_helper s acc = 
list_to_string (
List.rev_append (
string_to_list s) (
string_to_list acc)).
  Proof.
  Lemma string_reverse_reverse s :
    
string_reverse s = 
list_to_string (
List.rev (
string_to_list s)).
  Proof.
  Lemma string_reverse_involutive x : 
string_reverse (
string_reverse x) = 
x.
  Proof.
  Lemma string_reverse_inj x y :
    
string_reverse x = 
string_reverse y -> 
    
x = 
y.
  Proof.
  Lemma lt_contr1 s1 s2 :
    ~
StringOrder.lt s1 s2 -> ~
StringOrder.lt s2 s1 -> 
StringOrder.eq s1 s2.
  Proof.
    unfold not; 
intros.
    
generalize (
StringOrder.trichotemy s1 s2); 
intros.
    
inversion H1.
    
elim H2; 
intros.
    
congruence.
    
assumption.
    
congruence.
  Qed.
 
  Lemma lt_contr2 s1 s2 :
    
StringOrder.lt s1 s2 -> ~
StringOrder.eq s1 s2.
  Proof.
    compare s1 s2.
    
intros. 
rewrite e in *; 
clear e.
    
unfold not; 
intros.
    
apply asymmetry with (
x := 
s2) (
y := 
s2); 
assumption.
    
intros. 
assumption.
    
apply ascii_dec.
  Qed.
 
  Lemma lt_contr3 s :
    
StringOrder.lt s s -> 
False.
  Proof.
    generalize (
lt_contr2 s s); 
intros.
    
unfold not in *.
    
apply (
H H0).
    
reflexivity.
  Qed.
 
End AsciiToString.
Section Like.
  
Inductive like_clause :=
  | 
like_literal (
literal:
string) : 
like_clause
  | 
like_any_char : 
like_clause
  | 
like_any_string : 
like_clause.
  
Fixpoint make_like_clause (
s:
string) (
escape:
option ascii) {
struct s}: 
list like_clause
    := 
match s with
       | 
EmptyString => 
nil
       | 
String "
_"%
char tail => 
like_any_char :: 
make_like_clause tail escape
       | 
String "%"%
char tail => 
like_any_string :: 
make_like_clause tail escape
       | 
other =>
         (
fix make_like_literal_clause (
ss:
string)  (
acc:
string) {
struct ss} : 
list like_clause
          := 
match ss with
             | 
EmptyString => 
like_literal (
string_reverse acc) :: 
nil
             | 
String "
_"%
char tail => 
like_literal (
string_reverse acc) :: 
like_any_char :: 
make_like_clause tail escape
             | 
String "%"%
char tail => 
like_literal (
string_reverse acc) :: 
like_any_string :: 
make_like_clause tail escape
             | 
String h tail =>
               
if Some h == 
escape
               then
                 match tail with
                 | 
EmptyString =>
                   
like_literal (
string_reverse (
String h acc)) :: 
nil
                 | 
String "
_"%
char tail => 
make_like_literal_clause tail (
String "
_" 
acc)
                 | 
String "%"%
char tail => 
make_like_literal_clause tail (
String "%" 
acc)
                 | 
String nh ntail =>
                   
if Some nh == 
escape
                   then make_like_literal_clause ntail (
String nh acc)
                   
else
                     make_like_literal_clause ntail (
String nh (
String h acc))
                 
end
               else
                 make_like_literal_clause tail (
String h acc)
             
end
         ) 
other ""%
string
       end.
  
Example make_like_clause_example1 := 
make_like_clause "
hello_there^^^%%" 
None.
  
Example make_like_clause_example2 := 
make_like_clause "
hello_there^^^%%" (
Some "^"%
char).
  
Fixpoint  string_exists_suffix (
f:
string->
bool) (
s:
string) : 
bool
    := 
f s ||
         
match s with
         | 
EmptyString => 
false
         | 
String _ tail => 
string_exists_suffix f tail
         end.
  
Fixpoint like_clause_matches_string (
pat:
list like_clause) (
s:
string)
    := 
match pat with
       | 
nil => 
s ==
b EmptyString
       | (
like_literal literal)::
rest =>
         
andb (
prefix literal s)
              (
like_clause_matches_string rest (
substring (
String.length literal) (
String.length s - 
String.length literal) 
s))
       | 
like_any_char::
rest =>
         
match s with
         | 
EmptyString => 
false
         | 
String _ tail => 
like_clause_matches_string rest tail
         end
       | 
like_any_string::
rest =>
         
string_exists_suffix (
like_clause_matches_string rest) 
s
       end.
  
  
Definition string_like (
str pattern:
string) (
escape:
option ascii) : 
bool
    := 
let pat_clause := 
make_like_clause pattern escape in
       like_clause_matches_string pat_clause str.
  
Example string_like_example1 := 
string_like "
hello there" "
hello there" 
None.
  
Example string_like_example2 := 
string_like "
hello there" "
hello %
there" 
None.
  
Example string_like_example3 := 
string_like "
hello there" "
he%
th_re" 
None.
  
Example string_like_example4 := 
string_like "
hello there " "
he%
th_re" 
None.
  
Example string_like_example5 := 
string_like "
hello thethare" "
he%
th_re" 
None.
  
Example string_like_example6 := 
string_like "
hello thetheare" "
he%
th_re" 
None.
  
End Like.