(* -*- coding: utf-8 -*- *)
(************************************************************************)
(*         *   The Coq Proof Assistant / The Coq Development Team       *)
(*  v      *   INRIA, CNRS and contributors - Copyright 1999-2018       *)
(* <O___,, *       (see CREDITS file for the list of authors)           *)
(*   \VV/  **************************************************************)
(*    //   *    This file is distributed under the terms of the         *)
(*         *     GNU Lesser General Public License Version 2.1          *)
(*         *     (see LICENSE file for the text of the license)         *)
(************************************************************************)
(** Contributed by Laurent Théry (INRIA); Adapted to Coq V8 by the Coq Development Team *)
(** *** Definition of strings *)
(** Implementation of string as list of ascii characters *)
Inductive string : Set :=
| EmptyString : string
| String : ascii -> string -> string.
Declare Scope string_scope.
Delimit Scope string_scope with string.
Bind Scope string_scope with string.
Local Open Scope string_scope.
Register EmptyString as plugins.syntax.EmptyString.
Register String as plugins.syntax.String.
(** Equality is decidable *)
Definition string_dec : forall s1 s2 : string, {s1 = s2} + {s1 <> s2}.
Local Ltac t_eqb :=
repeat first [ congruence
| progress subst
| apply conj
| match goal with
| [ |- context[eqb ?x ?y] ] => destruct (eqb_spec x y)
end
| intro ].
(** The first elements of [s1 ++ s2] are the ones of [s1] *)
(** The last elements of [s1 ++ s2] are the ones of [s2] *)
(** *** Substrings *)
(** [substring n m s] returns the substring of [s] that starts at position [n] and of length [m]; if this does not make sense it returns [""] *)
Fixpoint substring (n m : nat) (s : string) : string :=
match n, m, s with
| O, O, _ => EmptyString
| O, S m', EmptyString => s
| O, S m', String c s' => String c (substring 0 m' s')
| S n', _, EmptyString => s
| S n', _, String c s' => substring n' m s'
end.
(** The substring is included in the initial string *)
(** The substring has at most [m] elements *)
(** *** Concatenating lists of strings *)
(** [concat sep sl] concatenates the list of strings [sl], inserting the separator string [sep] between each. *)
Fixpoint concat (sep : string) (ls : list string) :=
match ls with
| nil => EmptyString
| cons x nil => x
| cons x xs => x ++ sep ++ concat sep xs
end.
(** *** Test functions *)
(** Test if [s1] is a prefix of [s2] *)
Fixpoint prefix (s1 s2 : string) {struct s2} : bool :=
match s1 with
| EmptyString => true
| String a s1' =>
match s2 with
| EmptyString => false
| String b s2' =>
match ascii_dec a b with
| left _ => prefix s1' s2'
| right _ => false
end
end
end.
(** If [s1] is a prefix of [s2], it is the [substring] of length [length s1] starting at position [O] of [s2] *)
(** Test if, starting at position [n], [s1] occurs in [s2]; if so it returns the position *)
Fixpoint index (n : nat) (s1 s2 : string) : option nat :=
match s2, n with
| EmptyString, O =>
match s1 with
| EmptyString => Some O
| String a s1' => None
end
| EmptyString, S n' => None
| String b s2', O =>
if prefix s1 s2 then Some O
else
match index O s1 s2' with
| Some n => Some (S n)
| None => None
end
| String b s2', S n' =>
match index n' s1 s2' with
| Some n => Some (S n)
| None => None
end
end.
(* Dirty trick to avoid locally that prefix reduces itself *)
Opaque prefix.
(** If the result of [index] is [Some m], [s1] in [s2] at position [m] *)
(** If the result of [index] is [Some m], [s1] does not occur in [s2] before [m] *)
(** If the result of [index] is [None], [s1] does not occur in [s2] after [n] *)

Theorem index_correct3 :
forall (n m : nat) (s1 s2 : string),
index n s1 s2 = None ->
s1 <> EmptyString -> n <= m -> substring m (length s1) s2 <> s1.