diff --git a/metadata/entries/Berlekamp_Zassenhaus.toml b/metadata/entries/Berlekamp_Zassenhaus.toml --- a/metadata/entries/Berlekamp_Zassenhaus.toml +++ b/metadata/entries/Berlekamp_Zassenhaus.toml @@ -1,56 +1,57 @@ title = "The Factorization Algorithm of Berlekamp and Zassenhaus" date = 2016-10-14 topics = [ "Mathematics/Algebra", ] abstract = """

We formalize the Berlekamp-Zassenhaus algorithm for factoring square-free integer polynomials in Isabelle/HOL. We further adapt an existing formalization of Yun’s square-free factorization algorithm to integer polynomials, and thus provide an efficient and certified factorization algorithm for arbitrary univariate polynomials.

The algorithm first performs a factorization in the prime field GF(p) and then performs computations in the integer ring modulo p^k, where both p and k are determined at runtime. Since a natural modeling of these structures via dependent types is not possible in Isabelle/HOL, we formalize the whole algorithm using Isabelle’s recent addition of local type definitions.

Through experiments we verify that our algorithm factors polynomials of degree 100 within seconds.

""" license = "bsd" note = "" [authors] [authors.divason] homepage = "divason_homepage" [authors.joosten] email = "joosten_email" [authors.thiemann] email = "thiemann_email" [authors.yamada] email = "yamada_email" [contributors] [notify] thiemann = "thiemann_email" [history] +2024-04-12 = "Added interface to simplify usage of generated code.
" [extra] [related] dois = [ "10.1007/s10817-019-09526-y", "10.1017/CBO9781139856065" ] pubs = [ "Wikipedia" ] diff --git a/metadata/entries/Polynomial_Factorization.toml b/metadata/entries/Polynomial_Factorization.toml --- a/metadata/entries/Polynomial_Factorization.toml +++ b/metadata/entries/Polynomial_Factorization.toml @@ -1,42 +1,43 @@ title = "Polynomial Factorization" date = 2016-01-29 topics = [ "Mathematics/Algebra", ] abstract = """ Based on existing libraries for polynomial interpolation and matrices, we formalized several factorization algorithms for polynomials, including Kronecker's algorithm for integer polynomials, Yun's square-free factorization algorithm for field polynomials, and Berlekamp's algorithm for polynomials over finite fields. By combining the last one with Hensel's lifting, we derive an efficient factorization algorithm for the integer polynomials, which is then lifted for rational polynomials by mechanizing Gauss' lemma. Finally, we assembled a combined factorization algorithm for rational polynomials, which combines all the mentioned algorithms and additionally uses the explicit formula for roots of quadratic polynomials and a rational root test.

As side products, we developed division algorithms for polynomials over integral domains, as well as primality-testing and prime-factorization algorithms for integers.""" license = "bsd" note = "" [authors] [authors.thiemann] email = "thiemann_email" [authors.yamada] email = "yamada_email" [contributors] [notify] thiemann = "thiemann_email" yamada = "yamada_email1" [history] +2024-04-12 = "changed definition of square-free-factorization.
" [extra] [related] diff --git a/metadata/entries/Show.toml b/metadata/entries/Show.toml --- a/metadata/entries/Show.toml +++ b/metadata/entries/Show.toml @@ -1,37 +1,38 @@ title = "Haskell's Show Class in Isabelle/HOL" date = 2014-07-29 topics = [ "Computer science/Functional programming", ] abstract = """ We implemented a type class for \"to-string\" functions, similar to Haskell's Show class. Moreover, we provide instantiations for Isabelle/HOL's standard types like bool, prod, sum, nats, ints, and rats. It is further possible, to automatically derive show functions for arbitrary user defined datatypes similar to Haskell's \"deriving Show\".""" license = "lgpl" note = "" [authors] [authors.sternagel] email = "sternagel_email" [authors.thiemann] email = "thiemann_email" [contributors] [notify] sternagel = "sternagel_email1" thiemann = "thiemann_email" [history] 2015-03-11 = "Adapted development to new-style (BNF-based) datatypes.
" 2015-04-10 = """ Moved development for old-style datatypes into subdirectory \"Old_Datatype\".
""" +2024-04-12 = "Added show-class based on string literals, added parsers for nat and int, added injectivity proofs.
" [extra] [related] diff --git a/metadata/entries/XML.toml b/metadata/entries/XML.toml --- a/metadata/entries/XML.toml +++ b/metadata/entries/XML.toml @@ -1,36 +1,41 @@ title = "XML" date = 2014-10-03 topics = [ "Computer science/Functional programming", "Computer science/Data structures", ] abstract = """ This entry provides an XML library for Isabelle/HOL. This includes parsing and pretty printing of XML trees as well as combinators for transforming XML trees into arbitrary user-defined data. The main contribution of this entry is an interface (fit for code generation) that allows for communication between verified programs formalized in Isabelle/HOL and the outside world via XML. This library was developed as part of the IsaFoR/CeTA project to which we refer for examples of its usage.""" license = "bsd" note = "" [authors] [authors.sternagel] email = "sternagel_email" [authors.thiemann] email = "thiemann_email" +[authors.yamada] +email = "yamada_email" + [contributors] [notify] sternagel = "sternagel_email" thiemann = "thiemann_email" +yamada = "yamada_email" [history] +2024-04-12 = "Switched to new XML-transformers, developed by Akihisa Yamada.
" [extra] [related] diff --git a/thys/Show/Number_Parser.thy b/thys/Show/Number_Parser.thy new file mode 100644 --- /dev/null +++ b/thys/Show/Number_Parser.thy @@ -0,0 +1,166 @@ +(* +Author: Christian Sternagel +Author: René Thiemann +*) + +text \We provide two parsers for natural numbers and integers, which are + verified in the sense that they are the inverse of the show-function for + these types. We therefore also prove that the show-functions are injective.\ +theory Number_Parser + imports + Show_Instances +begin + +text \We define here the bind-operations for option and sum-type. We do not + import these operations from Certification_Monads.Strict-Sum and Parser-Monad, + since these imports would yield a cyclic dependency of + the two AFP entries Show and Certification-Monads.\ + +definition obind where "obind opt f = (case opt of None \ None | Some x \ f x)" +definition sbind where "sbind su f = (case su of Inl e \ Inl e | Inr r \ f r)" + +context begin + +text \A natural number parser which is proven correct:\ + +definition nat_of_digit :: "char \ nat option" where + "nat_of_digit x \ + if x = CHR ''0'' then Some 0 + else if x = CHR ''1'' then Some 1 + else if x = CHR ''2'' then Some 2 + else if x = CHR ''3'' then Some 3 + else if x = CHR ''4'' then Some 4 + else if x = CHR ''5'' then Some 5 + else if x = CHR ''6'' then Some 6 + else if x = CHR ''7'' then Some 7 + else if x = CHR ''8'' then Some 8 + else if x = CHR ''9'' then Some 9 + else None" + +private fun nat_of_string_aux :: "nat \ string \ nat option" + where + "nat_of_string_aux n [] = Some n" | + "nat_of_string_aux n (d # s) = (obind (nat_of_digit d) (\m. nat_of_string_aux (10 * n + m) s))" + +definition "nat_of_string s \ + case if s = [] then None else nat_of_string_aux 0 s of + None \ Inl (STR ''cannot convert \"'' + String.implode s + STR ''\" to a number'') + | Some n \ Inr n" + +private lemma nat_of_string_aux_snoc: + "nat_of_string_aux n (s @ [c]) = + obind (nat_of_string_aux n s) (\ l. obind (nat_of_digit c) (\ m. Some (10 * l + m)))" + by (induct s arbitrary:n, auto simp: obind_def split: option.splits) + +private lemma nat_of_string_aux_digit: + assumes m10: "m < 10" + shows "nat_of_string_aux n (s @ string_of_digit m) = + obind (nat_of_string_aux n s) (\ l. Some (10 * l + m))" +proof - + from m10 have "m = 0 \ m = 1 \ m = 2 \ m = 3 \ m = 4 \ m = 5 \ m = 6 \ m = 7 \ m = 8 \ m = 9" + by presburger + thus ?thesis by (auto simp add: nat_of_digit_def nat_of_string_aux_snoc string_of_digit_def + obind_def split: option.splits) +qed + + +private lemmas shows_move = showsp_nat_append[of 0 _ "[]",simplified, folded shows_prec_nat_def] + +private lemma nat_of_string_aux_show: "nat_of_string_aux 0 (show m) = Some m" +proof (induct m rule:less_induct) + case IH: (less m) + show ?case proof (cases "m < 10") + case m10: True + show ?thesis + apply (unfold shows_prec_nat_def) + apply (subst showsp_nat.simps) + using m10 nat_of_string_aux_digit[OF m10, of 0 "[]"] + by (auto simp add:shows_string_def nat_of_string_def string_of_digit_def obind_def) + next + case m: False + then have "m div 10 < m" by auto + note IH = IH[OF this] + show ?thesis apply (unfold shows_prec_nat_def, subst showsp_nat.simps) + using m apply (simp add: shows_prec_nat_def[symmetric] shows_string_def) + apply (subst shows_move) + using nat_of_string_aux_digit m IH + by (auto simp: nat_of_string_def obind_def) + qed +qed + +lemma fixes m :: nat shows show_nonemp: "show m \ []" + apply (unfold shows_prec_nat_def) + apply (subst showsp_nat.simps) + apply (fold shows_prec_nat_def) + apply (unfold o_def) + apply (subst shows_move) + apply (auto simp: shows_string_def string_of_digit_def) + done + +text \The parser \nat_of_string\ is the inverse of \show\.\ +lemma nat_of_string_show[simp]: "nat_of_string (show m) = Inr m" + using nat_of_string_aux_show by (auto simp: nat_of_string_def show_nonemp) + +end + + +text \We also provide a verified parser for integers.\ + +fun safe_head where "safe_head [] = None" | "safe_head (x#xs) = Some x" + +definition int_of_string :: "string \ String.literal + int" + where "int_of_string s \ + if safe_head s = Some (CHR ''-'') then sbind (nat_of_string (tl s)) (\ n. Inr (- int n)) + else sbind (nat_of_string s) (\ n. Inr (int n))" + +definition digits :: "char set" where + "digits = set (''0123456789'')" + +lemma set_string_of_digit: "set (string_of_digit x) \ digits" + unfolding digits_def string_of_digit_def by auto + +lemma range_showsp_nat: "set (showsp_nat p n s) \ digits \ set s" +proof (induct p n arbitrary: s rule: showsp_nat.induct) + case (1 p n s) + then show ?case using set_string_of_digit[of n] set_string_of_digit[of "n mod 10"] + by (auto simp: showsp_nat.simps[of p n] shows_string_def) fastforce +qed + +lemma set_show_nat: "set (show (n :: nat)) \ digits" + using range_showsp_nat[of 0 n Nil] unfolding shows_prec_nat_def by auto + +lemma int_of_string_show[simp]: "int_of_string (show x) = Inr x" +proof - + have "show x = showsp_int 0 x []" + by (simp add: shows_prec_int_def) + also have "\ = (if x < 0 then ''-'' @ show (nat (-x)) else show (nat x))" + unfolding showsp_int_def if_distrib shows_prec_nat_def + by (simp add: shows_string_def) + also have "int_of_string \ = Inr x" + proof (cases "x < 0") + case True + thus ?thesis unfolding int_of_string_def sbind_def by simp + next + case False + from set_show_nat have "set (show (nat x)) \ digits" . + hence "CHR ''-'' \ set (show (nat x))" unfolding digits_def by auto + hence "safe_head (show (nat x)) \ Some CHR ''-''" + by (cases "show (nat x)", auto) + thus ?thesis using False + by (simp add: int_of_string_def sbind_def) + qed + finally show ?thesis . +qed + +hide_const (open) obind sbind + +text \Eventually, we derive injectivity of the show-functions for nat and int.\ + +lemma inj_show_nat: "inj (show :: nat \ string)" + by (rule inj_on_inverseI[of _ "\ s. case nat_of_string s of Inr x \ x"], auto) + +lemma inj_show_int: "inj (show :: int \ string)" + by (rule inj_on_inverseI[of _ "\ s. case int_of_string s of Inr x \ x"], auto) + + +end \ No newline at end of file diff --git a/thys/Show/ROOT b/thys/Show/ROOT --- a/thys/Show/ROOT +++ b/thys/Show/ROOT @@ -1,21 +1,22 @@ chapter AFP session Show = Deriving + options [timeout = 600] sessions "HOL-Computational_Algebra" theories Show_Instances Show_Poly Show_Complex Show_Real_Impl Shows_Literal + Number_Parser document_files "root.bib" "root.tex" session Old_Datatype_Show in "Old_Datatype" = Datatype_Order_Generator + options [timeout = 600] theories Old_Show_Instances Old_Show_Examples diff --git a/thys/Show/Show_Instances.thy b/thys/Show/Show_Instances.thy --- a/thys/Show/Show_Instances.thy +++ b/thys/Show/Show_Instances.thy @@ -1,335 +1,163 @@ (* Title: Show Author: Christian Sternagel Author: René Thiemann Maintainer: Christian Sternagel Maintainer: René Thiemann *) section \Instances of the Show Class for Standard Types\ theory Show_Instances imports Show HOL.Rat begin definition showsp_unit :: "unit showsp" where "showsp_unit p x = shows_string ''()''" lemma show_law_unit [show_law_intros]: "show_law showsp_unit x" by (rule show_lawI) (simp add: showsp_unit_def show_law_simps) abbreviation showsp_char :: "char showsp" where "showsp_char \ shows_prec" lemma show_law_char [show_law_intros]: "show_law showsp_char x" by (rule show_lawI) (simp add: show_law_simps) primrec showsp_bool :: "bool showsp" where "showsp_bool p True = shows_string ''True''" | "showsp_bool p False = shows_string ''False''" lemma show_law_bool [show_law_intros]: "show_law showsp_bool x" by (rule show_lawI, cases x) (simp_all add: show_law_simps) primrec pshowsp_prod :: "(shows \ shows) showsp" where "pshowsp_prod p (x, y) = shows_string ''('' o x o shows_string '', '' o y o shows_string '')''" (*NOTE: in order to be compatible with automatically generated show funtions, show-arguments of "map"-functions need to get precedence 1 (which may lead to redundant parentheses in the output, but seems unavoidable in the current setup, i.e., pshowsp via primrec followed by defining showsp via pshowsp composed with map).*) definition showsp_prod :: "'a showsp \ 'b showsp \ ('a \ 'b) showsp" where [code del]: "showsp_prod s1 s2 p = pshowsp_prod p o map_prod (s1 1) (s2 1)" lemma showsp_prod_simps [simp, code]: "showsp_prod s1 s2 p (x, y) = shows_string ''('' o s1 1 x o shows_string '', '' o s2 1 y o shows_string '')''" by (simp add: showsp_prod_def) lemma show_law_prod [show_law_intros]: "(\x. x \ Basic_BNFs.fsts y \ show_law s1 x) \ (\x. x \ Basic_BNFs.snds y \ show_law s2 x) \ show_law (showsp_prod s1 s2) y" proof (induct y) case (Pair x y) note * = Pair [unfolded prod_set_simps] show ?case by (rule show_lawI) (auto simp del: o_apply intro!: o_append intro: show_lawD * simp: show_law_simps) qed -fun string_of_digit :: "nat \ string" +definition string_of_digit :: "nat \ string" where "string_of_digit n = (if n = 0 then ''0'' else if n = 1 then ''1'' else if n = 2 then ''2'' else if n = 3 then ''3'' else if n = 4 then ''4'' else if n = 5 then ''5'' else if n = 6 then ''6'' else if n = 7 then ''7'' else if n = 8 then ''8'' else ''9'')" fun showsp_nat :: "nat showsp" where "showsp_nat p n = (if n < 10 then shows_string (string_of_digit n) else showsp_nat p (n div 10) o shows_string (string_of_digit (n mod 10)))" declare showsp_nat.simps [simp del] lemma show_law_nat [show_law_intros]: "show_law showsp_nat n" by (rule show_lawI, induct n rule: nat_less_induct) (simp add: show_law_simps showsp_nat.simps) lemma showsp_nat_append [show_law_simps]: "showsp_nat p n (x @ y) = showsp_nat p n x @ y" by (intro show_lawD show_law_intros) definition showsp_int :: "int showsp" where "showsp_int p i = (if i < 0 then shows_string ''-'' o showsp_nat p (nat (- i)) else showsp_nat p (nat i))" lemma show_law_int [show_law_intros]: "show_law showsp_int i" by (rule show_lawI, cases "i < 0") (simp_all add: showsp_int_def show_law_simps) lemma showsp_int_append [show_law_simps]: "showsp_int p i (x @ y) = showsp_int p i x @ y" by (intro show_lawD show_law_intros) definition showsp_rat :: "rat showsp" where "showsp_rat p x = (case quotient_of x of (d, n) \ if n = 1 then showsp_int p d else showsp_int p d o shows_string ''/'' o showsp_int p n)" lemma show_law_rat [show_law_intros]: "show_law showsp_rat r" by (rule show_lawI, cases "quotient_of r") (simp add: showsp_rat_def show_law_simps) lemma showsp_rat_append [show_law_simps]: "showsp_rat p r (x @ y) = showsp_rat p r x @ y" by (intro show_lawD show_law_intros) text \ Automatic show functions are not used for @{type unit}, @{type prod}, and numbers: for @{type unit} and @{type prod}, we do not want to display @{term "''Unity''"} and @{term "''Pair''"}; for @{type nat}, we do not want to display @{term "''Suc (Suc (... (Suc 0) ...))''"}; and neither @{type int} nor @{type rat} are datatypes. \ local_setup \ Show_Generator.register_foreign_partial_and_full_showsp @{type_name prod} 0 @{term "pshowsp_prod"} @{term "showsp_prod"} (SOME @{thm showsp_prod_def}) @{term "map_prod"} (SOME @{thm prod.map_comp}) [true, true] @{thm show_law_prod} #> Show_Generator.register_foreign_showsp @{typ unit} @{term "showsp_unit"} @{thm show_law_unit} #> Show_Generator.register_foreign_showsp @{typ bool} @{term "showsp_bool"} @{thm show_law_bool} #> Show_Generator.register_foreign_showsp @{typ char} @{term "showsp_char"} @{thm show_law_char} #> Show_Generator.register_foreign_showsp @{typ nat} @{term "showsp_nat"} @{thm show_law_nat} #> Show_Generator.register_foreign_showsp @{typ int} @{term "showsp_int"} @{thm show_law_int} #> Show_Generator.register_foreign_showsp @{typ rat} @{term "showsp_rat"} @{thm show_law_rat} \ derive "show" option sum prod unit bool nat int rat export_code "shows_prec :: 'a::show option showsp" "shows_prec :: ('a::show, 'b::show) sum showsp" "shows_prec :: ('a::show \ 'b::show) showsp" "shows_prec :: unit showsp" "shows_prec :: char showsp" "shows_prec :: bool showsp" "shows_prec :: nat showsp" "shows_prec :: int showsp" "shows_prec :: rat showsp" checking -text \In the sequel we prove injectivity of @{term "show :: nat \ string"}.\ - -lemma string_of_digit_inj: - assumes "x < y \ y < 10" - shows "string_of_digit x \ string_of_digit y" - using assms - apply (cases "y=1", simp) - apply (cases "y=2", simp) - apply (cases "y=3", simp) - apply (cases "y=4", simp) - apply (cases "y=5", simp) - apply (cases "y=6", simp) - apply (cases "y=7", simp) - apply (cases "y=8", simp) - apply (cases "y=9", simp) - by arith - - -lemma string_of_digit_inj_2: - assumes "x < 10" - shows "length (string_of_digit x) = 1" - using assms - apply (cases "x=0", simp) - apply (cases "x=1", simp) - apply (cases "x=2", simp) - apply (cases "x=3", simp) - apply (cases "x=4", simp) - apply (cases "x=5", simp) - apply (cases "x=6", simp) - apply (cases "x=7", simp) - apply (cases "x=8", simp) - apply (cases "x=9", simp) - by arith - -declare string_of_digit.simps[simp del] - -lemma string_of_digit_inj_1: - assumes "x < 10" and "y < 10" and "x \ y" - shows "string_of_digit x \ string_of_digit y" -proof - assume ass: "string_of_digit x = string_of_digit y" - with assms have "\ xx yy :: nat. xx < 10 \ yy < 10 \ xx < yy \ string_of_digit xx = string_of_digit yy" - proof (cases "x < y", blast) - case False - with \x \ y\ have "y < x" by arith - with assms ass have "y < 10 \ x < 10 \ y < x \ string_of_digit y = string_of_digit x" by auto - then show ?thesis by blast - qed - from this obtain xx yy :: nat where cond: "xx < 10 \ yy < 10 \ xx < yy \ string_of_digit xx = string_of_digit yy" by blast - then show False using string_of_digit_inj by auto -qed - -lemma shows_prec_nat_simp1: - fixes n::nat assumes "\ n < 10" shows "shows_prec d n xs = ((shows_prec d (n div 10) \ shows_string (string_of_digit (n mod 10)))) xs" - using showsp_nat.simps[of d n] - unfolding if_not_P[OF assms] shows_string_def o_def - unfolding shows_prec_nat_def by simp - -lemma show_nat_simp1: "\ (n::nat) < 10 \ show n = show (n div 10) @ string_of_digit (n mod 10)" - using shows_prec_nat_simp1[of n "0::nat" "[]"] unfolding shows_string_def o_def - unfolding shows_prec_append[symmetric] by simp - -lemma show_nat_len_1: fixes x :: nat - shows "length (show x) > 0" -proof (cases "x < 10") - assume ass: "\ x < 10" - then have "show x = show (x div 10) @ string_of_digit (x mod 10)" by (rule show_nat_simp1) - then have "length (show x) = length (show (x div 10)) + length (string_of_digit (x mod 10))" - unfolding length_append[symmetric] by simp - with ass show ?thesis by (simp add: string_of_digit_inj_2) -next - assume "x < 10" then show ?thesis - unfolding shows_prec_nat_def - unfolding showsp_nat.simps[of 0 x] - unfolding shows_string_def by (simp add: string_of_digit_inj_2) -qed - -lemma shows_prec_nat_simp2: - fixes n::nat assumes "n < 10" shows "shows_prec d n xs = string_of_digit n @ xs" - using showsp_nat.simps[of d n] - unfolding shows_prec_nat_def if_P[OF assms] shows_string_def by simp - -lemma show_nat_simp2: - fixes n::nat assumes "n < 10" shows "show n = string_of_digit n" - using shows_prec_nat_simp2[OF assms, of "0::nat" "[]"] by simp - -lemma show_nat_len_2: - fixes x :: nat - assumes one: "length (show x) = 1" - shows "x < 10" -proof (rule ccontr) - assume ass: "\ x < 10" - then have "show x = show (x div 10) @ string_of_digit (x mod 10)" by (rule show_nat_simp1) - then have "length (show x) = length (show (x div 10)) + length (string_of_digit (x mod 10))" - unfolding length_append[symmetric] by simp - with one have "length (show (x div 10)) = 0" by (simp add: string_of_digit_inj_2) - with show_nat_len_1 show False by best -qed - -lemma show_nat_len_3: - fixes x :: nat - assumes one: "length (show x) > 1" - shows "\ x < 10" -proof - assume ass: "x < 10" - then have "show x = string_of_digit x" by (rule show_nat_simp2) - with string_of_digit_inj_2 ass have "length (show x) = 1" by simp - with one show False by arith -qed - -lemma inj_show_nat: "inj (show::nat \ string)" - unfolding inj_on_def -proof (clarify) - fix x y :: nat assume "show x = show y" - then obtain n where "length (show x) = n \ show x = show y" by blast - then show "x = y" - proof (induct n arbitrary: x y) - case 0 - fix x y :: nat - assume ass: "length (show x) = 0 \ show x = show y" - then show ?case using show_nat_len_1 by best - next - case (Suc n) - then have eq: "show x = show y" by blast - from Suc have len: "length (show x) = Suc n" by blast - show ?case - proof (cases n) - case 0 - with Suc have one: "length(show x) = 1 \ length (show y) = 1" by (auto) - with show_nat_len_2 have ten: "x < 10 \ y < 10" by simp - show ?thesis - proof (cases "x = y", simp) - case False - with ten string_of_digit_inj_1 have "string_of_digit x \ string_of_digit y" by auto - with ten eq show ?thesis using show_nat_simp2[of x] show_nat_simp2[of y] by simp - qed - next - case (Suc m) - with len eq have "length (show x) = Suc (Suc m) \ length (show y) = Suc (Suc m)" by auto - then have "length (show x) > 1 \ length (show y) > 1" by simp - then have large: "\ x < 10 \ \ y < 10" using show_nat_len_3 by simp - let ?e = "\x::nat. show (x div 10) @ string_of_digit (x mod 10)" - from large have id: "show x = ?e x \ show y = ?e y" - using show_nat_simp1[of x] show_nat_simp1[of y] by auto - from string_of_digit_inj_2 have one: "length (string_of_digit(x mod 10)) = 1 - \ length(string_of_digit(y mod 10)) = 1" by auto - from one have "\xx. string_of_digit(x mod 10) = [xx]" - by (cases "string_of_digit (x mod 10)",simp,cases "tl (string_of_digit (x mod 10))",simp,simp) - from this obtain xx where xx: "string_of_digit(x mod 10) = [xx]" .. - from one have "\xx. string_of_digit(y mod 10) = [xx]" - by (cases "string_of_digit (y mod 10)",simp,cases "tl (string_of_digit (y mod 10))",simp,simp) - from this obtain yy where yy: "string_of_digit(y mod 10) = [yy]" .. - from id have "length (show x) = length (show (x div 10)) + length (string_of_digit (x mod 10))" unfolding length_append[symmetric] by simp - with one len have shorter: "length (show (x div 10)) = n" by simp - from eq id xx yy - have "(show (x div 10) @ [xx]) = (show (y div 10) @ [yy])" by simp - then have "(show (x div 10) = show(y div 10)) \ xx = yy" by clarify - then have nearly: "show (x div 10) = show (y div 10) - \ string_of_digit(x mod 10) = string_of_digit(y mod 10)" using xx yy by simp - with shorter and - \length (show (x div 10)) = n \ show (x div 10) = show (y div 10) \ x div 10 = y div 10\ - have div: "x div 10 = y div 10" by blast - from nearly string_of_digit_inj_1 have mod: "x mod 10 = y mod 10" - by (cases "x mod 10 = y mod 10", simp, simp) - have "x = 10 * (x div 10) + (x mod 10)" by auto - also have "\ = 10 * (y div 10) + (y mod 10)" using div mod by auto - also have "\ = y" by auto - finally show ?thesis . - qed - qed -qed - end diff --git a/thys/Show/Shows_Literal.thy b/thys/Show/Shows_Literal.thy --- a/thys/Show/Shows_Literal.thy +++ b/thys/Show/Shows_Literal.thy @@ -1,177 +1,177 @@ (* Title: Shows_Literal Author: René Thiemann Maintainer: René Thiemann *) section \Show Based on String Literals\ theory Shows_Literal imports Main - Show.Show_Real + Show_Real begin text \In this theory we provide an alternative to the @{class show}-class, where @{typ String.literal} instead of @{typ string} is used, with the aim that target-language readable strings are used in generated code. In particular when writing Isabelle functions that produce strings such as @{term "STR ''this is info for the user: ...''"}, this class might be useful. To keep it simple, in contrast to @{class show}, here we do not enforce the show law.\ type_synonym showsl = "String.literal \ String.literal" definition showsl_of_shows :: "shows \ showsl" where "showsl_of_shows shws s = String.implode (shws []) + s" definition showsl_lit :: "String.literal \ showsl" where "showsl_lit = (+)" definition "showsl_paren s = showsl_lit (STR ''('') o s o showsl_lit (STR '')'')" fun showsl_sep :: "('a \ showsl) \ showsl \ 'a list \ showsl" where "showsl_sep s sep [] = showsl_lit (STR '''')" | "showsl_sep s sep [x] = s x" | "showsl_sep s sep (x#xs) = s x o sep o showsl_sep s sep xs" definition showsl_list_gen :: "('a \ showsl) \ String.literal \ String.literal \ String.literal \ String.literal \ 'a list \ showsl" where "showsl_list_gen showslx e l s r xs = (if xs = [] then showsl_lit e else showsl_lit l o showsl_sep showslx (showsl_lit s) xs o showsl_lit r)" definition default_showsl_list :: "('a \ showsl) \ 'a list \ showsl" where "default_showsl_list sl = showsl_list_gen sl (STR ''[]'') (STR ''['') (STR '', '') (STR '']'')" definition [code_unfold]: "char_zero = (48 :: integer)" lemma char_zero: "char_zero = integer_of_char (CHR ''0'')" by code_simp fun lit_of_digit :: "nat \ String.literal" where "lit_of_digit n = String.implode [char_of_integer (char_zero + integer_of_nat n)]" class showl = fixes showsl :: "'a \ showsl" and showsl_list :: "'a list \ showsl" definition "showsl_lines desc_empty = showsl_list_gen showsl desc_empty (STR '''') (STR ''\'') (STR '''')" abbreviation showl where "showl x \ showsl x (STR '''')" instantiation char :: showl begin definition "showsl_char c = showsl_lit (String.implode [c])" \ \Shouldn't there be a faster conversion than via strings?\ definition "showsl_list_char cs s = showsl_lit (String.implode cs) s" instance .. end instantiation String.literal :: showl begin definition "showsl (s :: String.literal) = showsl_lit s" definition "showsl_list (xs :: String.literal list) = default_showsl_list showsl xs" instance .. end instantiation bool :: showl begin definition "showsl (b :: bool) = showsl_lit (if b then STR ''True'' else STR ''False'')" definition "showsl_list (xs :: bool list) = default_showsl_list showsl xs" instance .. end instantiation nat :: showl begin fun showsl_nat :: "nat \ showsl" where "showsl_nat n = (if n < 10 then showsl_lit (lit_of_digit n) else showsl_nat (n div 10) o showsl_lit (lit_of_digit (n mod 10)))" definition "showsl_list (xs :: nat list) = default_showsl_list showsl xs" instance .. end instantiation int :: showl begin definition "showsl_int i = (if i < 0 then showsl_lit (STR ''-'') o showsl (nat (- i)) else showsl (nat i))" definition "showsl_list (xs :: int list) = default_showsl_list showsl xs" instance .. end instantiation integer :: showl begin definition showsl_integer :: "integer \ showsl" where "showsl_integer i = showsl (int_of_integer i)" definition showsl_list_integer :: "integer list \ showsl" where "showsl_list_integer xs = default_showsl_list showsl xs" instance .. end instantiation rat :: showl begin definition "showsl_rat x = (case quotient_of x of (d, n) \ if n = 1 then showsl d else showsl d o showsl_lit (STR ''/'') o showsl n)" definition "showsl_list (xs :: rat list) = default_showsl_list showsl xs" instance .. end instantiation real :: showl begin definition "showsl (x :: real) = showsl_lit (String.implode (show_real x))" definition "showsl_list (xs :: real list) = default_showsl_list showsl xs" instance .. end instantiation unit :: showl begin definition "showsl (x :: unit) = showsl_lit (STR ''()'')" definition "showsl_list (xs :: unit list) = default_showsl_list showsl xs" instance .. end instantiation option :: (showl) showl begin fun showsl_option where "showsl_option None = showsl_lit (STR ''None'')" | "showsl_option (Some x) = showsl_lit (STR ''Some ('') o showsl x o showsl_lit (STR '')'')" definition "showsl_list (xs :: 'a option list) = default_showsl_list showsl xs" instance .. end instantiation sum :: (showl,showl) showl begin fun showsl_sum where "showsl_sum (Inl x) = showsl_lit (STR ''Inl ('') o showsl x o showsl_lit (STR '')'')" | "showsl_sum (Inr x) = showsl_lit (STR ''Inr ('') o showsl x o showsl_lit (STR '')'')" definition "showsl_list (xs :: ('a + 'b) list) = default_showsl_list showsl xs" instance .. end instantiation prod :: (showl,showl) showl begin fun showsl_prod where "showsl_prod (Pair x y) = showsl_lit (STR ''('') o showsl x o showsl_lit (STR '', '') o showsl y o showsl_lit (STR '')'')" definition "showsl_list (xs :: ('a * 'b) list) = default_showsl_list showsl xs" instance .. end definition [code_unfold]: "showsl_nl = showsl (STR ''\'')" definition add_index :: "showsl \ nat \ showsl" where "add_index s i = s o showsl_lit (STR ''.'') o showsl i" instantiation list :: (showl) showl begin definition showsl_list :: "'a list \ showsl" where "showsl_list (xs :: 'a list) = showl_class.showsl_list xs" definition "showsl_list_list (xs :: 'a list list) = default_showsl_list showsl xs" instance .. end end diff --git a/thys/XML/Example_Application.thy b/thys/XML/Example_Application.thy new file mode 100644 --- /dev/null +++ b/thys/XML/Example_Application.thy @@ -0,0 +1,51 @@ +(* +Author: René Thiemann +*) +theory Example_Application + imports + Xmlt +begin + +text \Let us consider inputs that consist of an optional number and a list of first order terms, + where these terms use strings as function names and numbers for variables. + We assume that we have a XML-document that describes these kinds of inputs and now want to parse them.\ + +definition exampleInput where "exampleInput = STR + '' + 42 + + fo<>bar + 1 + 3 + + 15 + ''" + +datatype fo_term = Fun string "fo_term list" | Var int + +definition var :: "fo_term xmlt" where "var = xml_change (xml_int (STR ''var'')) (xml_return \ Var)" + +text \a recursive parser is best defined via partial-function. Note that the xml-argument + should be provided, otherwise strict evalution languages will not terminate.\ +partial_function (sum_bot) parse_term :: "fo_term xmlt" +where + [code]: "parse_term xml = ( + XMLdo (STR ''funapp'') { + name \ xml_text (STR ''symbol''); + args \* parse_term; + xml_return (Fun name args) + } XMLor var) xml" + +text \for non-recursive parsers, we can eta-contract\ +definition parse_input :: "(int option \ fo_term list) xmlt" where + "parse_input = XMLdo (STR ''input'') { + onum \? xml_int (STR ''magicNumber''); + terms \* parse_term; + xml_return (onum,terms) + }" + +definition test where "test = parse_xml_string parse_input (String.explode exampleInput)" + +value test (* successfully parses the example input *) +export_code test checking SML +end \ No newline at end of file diff --git a/thys/XML/ROOT b/thys/XML/ROOT --- a/thys/XML/ROOT +++ b/thys/XML/ROOT @@ -1,11 +1,12 @@ chapter AFP session XML = "HOL-Library" + options [timeout = 600] sessions Certification_Monads Show theories Xmlt + Example_Application document_files "root.tex" diff --git a/thys/XML/Xml.thy b/thys/XML/Xml.thy --- a/thys/XML/Xml.thy +++ b/thys/XML/Xml.thy @@ -1,880 +1,880 @@ (* Title: Xml Author: Christian Sternagel Author: René Thiemann *) section \Parsing and Printing XML Documents\ theory Xml imports Certification_Monads.Parser_Monad "HOL-Library.Char_ord" "HOL-Library.Code_Abstract_Char" begin datatype xml = \ \node-name, attributes, child-nodes\ XML string "(string \ string) list" "xml list" | XML_text string datatype xmldoc = \ \header, body\ XMLDOC "string list" (root_node: xml) fun tag :: "xml \ string" where "tag (XML name _ _ ) = name" | "tag (XML_text _) = []" hide_const (open) tag fun children :: "xml \ xml list" where "children (XML _ _ cs) = cs" | "children (XML_text _) = []" hide_const (open) children fun num_children :: "xml \ nat" where "num_children (XML _ _ cs) = length cs" | "num_children (XML_text _) = 0" hide_const (open) num_children subsection \Printing of XML Nodes and Documents\ instantiation xml :: "show" begin definition shows_attr :: "string \ string \ shows" where "shows_attr av = shows (fst av) o shows_string (''=\"'' @ snd av @ ''\"'')" definition shows_attrs :: "(string \ string) list \ shows" where "shows_attrs as = foldr (\a. '' '' +#+ shows_attr a) as" fun shows_XML_indent :: "string \ nat \ xml \ shows" where "shows_XML_indent ind i (XML n a c) = (''\'' +#+ ind +#+ ''<'' +#+ shows n +@+ shows_attrs a +@+ (if c = [] then shows_string ''/>'' else ( ''>'' +#+ foldr (shows_XML_indent (replicate i (CHR '' '') @ ind) i) c +@+ ''\'' +#+ ind +#+ '''')))" | "shows_XML_indent ind i (XML_text t) = shows_string t" definition "shows_prec (d::nat) xml = shows_XML_indent '''' 2 xml" definition "shows_list (xs :: xml list) = showsp_list shows_prec 0 xs" lemma shows_attr_append: "(s +#+ shows_attr av) (r @ t) = (s +#+ shows_attr av) r @ t" unfolding shows_attr_def by (cases av) (auto simp: show_law_simps) lemma shows_attrs_append [show_law_simps]: "shows_attrs as (r @ s) = shows_attrs as r @ s" using shows_attr_append by (induct as) (simp_all add: shows_attrs_def) lemma append_xml': "shows_XML_indent ind i xml (r @ s) = shows_XML_indent ind i xml r @ s" by (induct xml arbitrary: ind r s) (auto simp: show_law_simps) lemma shows_prec_xml_append [show_law_simps]: "shows_prec d (xml::xml) (r @ s) = shows_prec d xml r @ s" unfolding shows_prec_xml_def by (rule append_xml') instance by standard (simp_all add: show_law_simps shows_list_xml_def) end instantiation xmldoc :: "show" begin fun shows_xmldoc where "shows_xmldoc (XMLDOC h x) = shows_lines h o shows_nl o shows x" definition "shows_prec (d::nat) doc = shows_xmldoc doc" definition "shows_list (xs :: xmldoc list) = showsp_list shows_prec 0 xs" lemma shows_prec_xmldoc_append [show_law_simps]: "shows_prec d (x::xmldoc) (r @ s) = shows_prec d x r @ s" by (cases x) (auto simp: shows_prec_xmldoc_def show_law_simps) instance by standard (simp_all add: show_law_simps shows_list_xmldoc_def) end subsection \XML-Parsing\ definition parse_text :: "string option parser" where "parse_text = do { ts \ many ((\) CHR ''<''); let text = trim ts; if text = [] then return None else return (Some (List.rev (trim (List.rev text)))) }" lemma is_parser_parse_text [intro]: "is_parser parse_text" by (auto simp: parse_text_def) lemma parse_text_consumes: assumes *: "ts \ []" "hd ts \ CHR ''<''" and parse: "parse_text ts = Inr (t, ts')" shows "length ts' < length ts" proof - from * obtain a tss where ts: "ts = a # tss" and not: "a \ CHR ''<''" by (cases ts, auto) note parse = parse [unfolded parse_text_def Let_def ts] from parse obtain x1 x2 where many: "many ((\) CHR ''<'') tss = Inr (x1, x2)" using not by (cases "many ((\) CHR ''<'') tss", auto simp: bind_def) from is_parser_many many have len: "length x2 \ length tss" by blast from parse many have "length ts' \ length x2" using not by (simp add: bind_def return_def split: if_splits) with len show ?thesis unfolding ts by auto qed definition parse_attribute_value :: "string parser" where "parse_attribute_value = do { exactly [CHR ''\"'']; v \ many ((\) CHR ''\"''); exactly [CHR ''\"'']; return v }" lemma is_parser_parse_attribute_value [intro]: "is_parser parse_attribute_value" by (auto simp: parse_attribute_value_def) text \A list of characters that are considered to be "letters" for tag-names.\ definition letters :: "char list" where "letters = ''abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789&;:-''" definition is_letter :: "char \ bool" where "is_letter c \ c \ set letters" lemma is_letter_pre_code: "is_letter c \ CHR ''a'' \ c \ c \ CHR ''z'' \ CHR ''A'' \ c \ c \ CHR ''Z'' \ CHR ''0'' \ c \ c \ CHR ''9'' \ c \ set ''_&;:-''" by (cases c) (simp add: less_eq_char_def is_letter_def letters_def) definition many_letters :: "string parser" where [simp]: "many_letters = manyof letters" lemma many_letters [code, code_unfold]: "many_letters = many is_letter" by (simp add: is_letter_def [abs_def] manyof_def) definition parse_name :: "string parser" where "parse_name s = (do { n \ many_letters; spaces; if n = [] then error (''expected letter '' @ letters @ '' but first symbol is \"'' @ take 1 s @ ''\"'') else return n }) s" lemma is_parser_parse_name [intro]: "is_parser parse_name" proof fix s r x assume res: "parse_name s = Inr (x, r)" let ?exp = "do { n \ many_letters; spaces; if n = [] then error (''expected letter '' @ letters @ '' but first symbol is \"'' @ take 1 s @ ''\"'') else return n }" have isp: "is_parser ?exp" by auto have id: "parse_name s = ?exp s" by (simp add: parse_name_def) from isp [unfolded is_parser_def, rule_format, OF res [unfolded id]] show "length r \ length s" . qed function (sequential) parse_attributes :: "(string \ string) list parser" where "parse_attributes [] = Error_Monad.return ([], [])" | "parse_attributes (c # s) = (if c \ set ''/>'' then Error_Monad.return ([], c # s) else (do { k \ parse_name; exactly ''=''; v \ parse_attribute_value; atts \ parse_attributes; return ((k, v) # atts) }) (c # s))" by pat_completeness auto termination parse_attributes proof show "wf (measure length)" by simp next fix c s y ts ya tsa yb tsb assume pn: "parse_name (c # s) = Inr (y, ts)" and oo: "exactly ''='' ts = Inr (ya, tsa)" and pav: "parse_attribute_value tsa = Inr (yb, tsb)" have cp: "is_cparser (exactly ''='')" by auto from cp [unfolded is_cparser_def] oo have 1: "length ts > length tsa" by auto from is_parser_parse_name [unfolded is_parser_def] pn have 2: "length (c # s) \ length ts" by force from is_parser_parse_attribute_value [unfolded is_parser_def] pav have 3: "length tsa \ length tsb" by force from 1 2 3 show "(tsb, c # s) \ measure length" by auto qed lemma is_parser_parse_attributes [intro]: "is_parser parse_attributes" proof fix s r x assume "parse_attributes s = Inr (x, r)" then show "length r \ length s" proof (induct arbitrary: x rule: parse_attributes.induct) case (2 c s) show ?case proof (cases "c \ set ''/>''") case True with 2(2) show ?thesis by simp next case False from False 2(2) obtain y1 s1 where pn: "parse_name (c # s) = Inr (y1, s1)" by (cases "parse_name (c # s)") (auto simp: bind_def) from False 2(2) pn obtain y2 s2 where oo: "exactly ''='' s1 = Inr (y2, s2)" by (cases "exactly ''='' s1") (auto simp: bind_def) from False 2(2) pn oo obtain y3 s3 where pav: "parse_attribute_value s2 = Inr (y3, s3)" by (cases "parse_attribute_value s2") (auto simp: bind_def) from False 2(2) pn oo pav obtain y4 where patts: "parse_attributes s3 = Inr (y4, r)" by (cases "parse_attributes s3") (auto simp: return_def bind_def) have "length r \ length s3" using 2(1)[OF False pn oo pav patts] . also have "\ \ length s2" using is_parser_parse_attribute_value [unfolded is_parser_def] pav by auto also have "\ \ length s1" using is_parser_exactly [unfolded is_parser_def] oo by auto also have "\ \ length (c # s)" using is_parser_parse_name [unfolded is_parser_def] pn by force finally show "length r \ length (c # s)" by auto qed qed simp qed context notes [[function_internals]] begin function parse_nodes :: "xml list parser" where "parse_nodes ts = (if ts = [] \ take 2 ts = '' CHR ''<'' then (do { t \ parse_text; ns \ parse_nodes; return (XML_text (the t) # ns) }) ts else (do { exactly ''<''; n \ parse_name; atts \ parse_attributes; e \ oneof [''/>'', ''>'']; (\ ts'. if e = ''/>'' then (do { cs \ parse_nodes; return (XML n atts [] # cs) }) ts' else (do { cs \ parse_nodes; exactly ''''; ns \ parse_nodes; return (XML n atts cs # ns) }) ts') }) ts)" by pat_completeness auto end lemma parse_nodes_help: "parse_nodes_dom s \ (\ x r. parse_nodes s = Inr (x, r) \ length r \ length s)" (is "?prop s") proof (induct rule: wf_induct [where P = ?prop and r = "measure length"]) fix s assume "\ t. (t, s) \ measure length \ ?prop t" then have ind1: "\ t. length t < length s \ parse_nodes_dom t" and ind2: "\ t x r. length t < length s \ parse_nodes t = Inr (x,r) \ length r \ length t" by auto let ?check = "\ s. s = [] \ take 2 s = '' CHR ''<''" have dom: "parse_nodes_dom s" proof fix y assume "parse_nodes_rel y s" then show "parse_nodes_dom y" proof fix ts ya tsa assume *: "y = tsa" "s = ts" "\ (ts = [] \ take 2 ts = '' CHR ''<''" and parse: "parse_text ts = Inr (ya, tsa)" from parse_text_consumes[OF _ _ parse] *(3-4) have "length tsa < length ts" by auto with * have len: "length s > length y" by simp from ind1[OF this] show "parse_nodes_dom y" . next fix ts ya tsa yaa tsb yb tsc yc tsd assume "y = tsd" and "s = ts" and "\ ?check ts" and "exactly ''<'' ts = Inr (ya, tsa)" and "parse_name tsa = Inr (yaa, tsb)" and "parse_attributes tsb = Inr (yb, tsc)" and "oneof [''/>'', ''>''] tsc = Inr (yc, tsd)" and "yc = ''/>''" then have len: "length s > length y" using is_cparser_exactly [of "''<''"] and is_parser_oneof [of "[''/>'', ''>'']"] and is_parser_parse_attributes and is_parser_parse_name by (auto dest!: is_parser_length is_cparser_length) with ind1[OF len] show "parse_nodes_dom y" by simp next fix ts ya tsa yaa tsb yb tsc yc tsd assume "y = tsd" and "s = ts" and "\ ?check ts" and "exactly ''<'' ts = Inr (ya, tsa)" and "parse_name tsa = Inr (yaa, tsb)" and "parse_attributes tsb = Inr (yb, tsc)" and "oneof [''/>'', ''>''] tsc = Inr (yc, tsd)" then have len: "length s > length y" using is_cparser_exactly [of "''<''", simplified] and is_parser_oneof [of "[''/>'', ''>'']"] and is_parser_parse_attributes and is_parser_parse_name by (auto dest!: is_parser_length is_cparser_length) with ind1[OF len] show "parse_nodes_dom y" by simp next fix ts ya tsa yaa tsb yb tsc yc tse ye tsf yf tsg yg tsh yh tsi yi tsj assume y: "y = tsj" and "s = ts" and "\ ?check ts" and "exactly ''<'' ts = Inr (ya, tsa)" and "parse_name tsa = Inr (yaa, tsb)" and "parse_attributes tsb = Inr (yb, tsc)" and "oneof [''/>'', ''>''] tsc = Inr (yc, tse)" and rec: "parse_nodes_sumC tse = Inr (ye, tsf)" and last: "exactly '''' tsh = Inr (yi, tsj)" then have len: "length s > length tse" using is_cparser_exactly [of "''<''", simplified] and is_parser_oneof [of "[''/>'', ''>'']"] and is_parser_parse_attributes and is_parser_parse_name by (auto dest!: is_parser_length is_cparser_length) from last(1) last(2) have len2a: "length tsf \ length tsh" using is_parser_exactly [of "'' length y" using last(3) using is_parser_exactly [of "''>''"] by (auto simp: y dest!: is_parser_length) from len2a len2c have len2: "length tsf \ length y" by simp from ind2[OF len rec[unfolded parse_nodes_def[symmetric]]] len len2 have "length s > length y" by simp from ind1[OF this] show "parse_nodes_dom y" . qed qed note psimps = parse_nodes.psimps[OF dom] show "?prop s" proof (intro conjI, rule dom, intro allI impI) fix x r assume res: "parse_nodes s = Inr (x,r)" note res = res[unfolded psimps] then show "length r \ length s" proof (cases "?check s") case True then show ?thesis using res by (simp add: return_def) next case False note oFalse = this show ?thesis proof (cases ?check2) case True note res = res[simplified False True, simplified] from res obtain y1 s1 where pt: "parse_text s = Inr (y1, s1)" by (cases "parse_text s", auto simp: bind_def) note res = res[unfolded bind_def pt, simplified] from res obtain y2 s2 where pn: "parse_nodes s1 = Inr (y2, s2)" by (cases "parse_nodes s1") (auto simp: bind_def) note res = res[simplified bind_def pn, simplified] from res have r: "r = s2" by (simp add: return_def bind_def) from parse_text_consumes[OF _ True pt] False have lens: "length s1 < length s" by auto from ind2[OF lens pn] have "length s2 \ length s1" . then show ?thesis using lens unfolding r by auto next case False note ooFalse = this note res = res[simplified oFalse ooFalse, simplified] from res obtain y1 s1 where oo: "exactly ''<'' s = Inr (y1, s1)" by (cases "exactly ''<'' s", auto simp: bind_def) note res = res[unfolded bind_def oo, simplified] from res obtain y2 s2 where pn: "parse_name s1 = Inr (y2, s2)" by (cases "parse_name s1") (auto simp: bind_def psimps) note res = res[simplified bind_def pn, simplified] from res obtain y3 s3 where pa: "parse_attributes s2 = Inr (y3, s3)" by (cases "parse_attributes s2") (auto simp: return_def bind_def) note res = res[simplified pa, simplified] from res obtain y4 s4 where oo2: "oneof [''/>'', ''>''] s3 = Inr (y4, s4)" by (cases "oneof [''/>'', ''>''] s3") (auto simp: return_def bind_def) note res = res[unfolded oo2, simplified] from is_parser_parse_attributes and is_parser_oneof [of "[''/>'', ''>'']"] and is_cparser_exactly [of "''<''", simplified] and is_parser_parse_name and oo pn pa oo2 have s_s4: "length s > length s4" by (auto dest!: is_parser_length is_cparser_length) show ?thesis proof (cases "y4 = ''/>''") case True from res True obtain y5 where pns: "parse_nodes s4 = Inr (y5, r)" by (cases "parse_nodes s4") (auto simp: return_def bind_def) from ind2[OF s_s4 pns] s_s4 show "length r \ length s" by simp next case False note res = res[simplified False, simplified] from res obtain y6 s6 where pns: "parse_nodes s4 = Inr (y6, s6)" by (cases "parse_nodes s4") (auto simp: return_def bind_def) note res = res[unfolded bind_def pns, simplified, unfolded bind_def] from res obtain y7 s7 where oo3: "exactly '''' s8 = Inr (y10,s10)" by (cases "exactly ''>'' s8", auto simp: bind_def) note res = res[unfolded oo5 bind_def, simplified] from res obtain y11 s11 where pns2: "parse_nodes s10 = Inr (y11, s11)" by (cases "parse_nodes s10", auto simp: bind_def) note res = res[unfolded bind_def pns2, simplified] note one = is_parser_oneof [unfolded is_parser_def, rule_format] note exact = is_parser_exactly [unfolded is_parser_def, rule_format] from ind2[OF s_s4 pns] s_s4 exact[OF oo3] exact[OF oo4] have s_s7: "length s > length s8" unfolding is_parser_def by force with exact[OF oo5] have s_s10: "length s > length s10" by simp with ind2[OF s_s10 pns2] have s_s11: "length s > length s11" by simp then show "length r \ length s" using res by (auto simp: return_def) qed qed qed qed qed simp termination parse_nodes using parse_nodes_help by blast lemma parse_nodes [intro]: "is_parser parse_nodes" unfolding is_parser_def using parse_nodes_help by blast text \A more efficient variant of @{term "oneof [''/>'', ''>'']"}.\ fun oneof_closed :: "string parser" where "oneof_closed (x # xs) = (if x = CHR ''>'' then Error_Monad.return (''>'', trim xs) else if x = CHR ''/'' \ (case xs of [] \ False | y # ys \ y = CHR ''>'') then Error_Monad.return (''/>'', trim (tl xs)) else err_expecting (''one of [/>, >]'') (x # xs))" | "oneof_closed xs = err_expecting (''one of [/>, >]'') xs" lemma oneof_closed: "oneof [''/>'', ''>''] = oneof_closed" (is "?l = ?r") proof (rule ext) fix xs have id: "''one of '' @ shows_list [''/>'', ''>''] [] = ''one of [/>, >]''" by (simp add: shows_list_list_def showsp_list_def pshowsp_list_def shows_list_gen_def shows_string_def shows_prec_list_def shows_list_char_def) note d = oneof_def oneof_aux.simps id show "?l xs = ?r xs" proof (cases xs) case Nil show ?thesis unfolding Nil d by simp next case (Cons x xs) note oCons = this show ?thesis proof (cases "x = CHR ''>''") case True show ?thesis unfolding Cons d True by simp next case False note oFalse = this show ?thesis proof (cases "x = CHR ''/''") case False show ?thesis unfolding Cons d using False oFalse by simp next case True show ?thesis proof (cases xs) case Nil show ?thesis unfolding Cons Nil d by auto next case (Cons y ys) show ?thesis unfolding oCons Cons d by simp qed qed qed qed qed lemma If_removal: "(\ e x. if b e then f e x else g e x) = (\ e. if b e then f e else g e)" by (intro ext) auto declare parse_nodes.simps [unfolded oneof_closed, unfolded If_removal [of "\ e. e = ''/>''"], code] definition parse_node :: "xml parser" where "parse_node = do { exactly ''<''; n \ parse_name; atts \ parse_attributes; e \ oneof [''/>'', ''>'']; if e = ''/>'' then return (XML n atts []) else do { cs \ parse_nodes; exactly ''''; return (XML n atts cs) } }" declare parse_node_def [unfolded oneof_closed, code] function parse_header :: "string list parser" where "parse_header ts = (if take 2 (trim ts) = '' scan_upto ''?>''; hs \ parse_header; return (h # hs) }) ts else (do { spaces; return [] }) ts)" by pat_completeness auto termination parse_header proof fix ts y tsa assume "scan_upto ''?>'' ts = Inr (y, tsa)" with is_cparser_scan_upto have "length ts > length tsa" unfolding is_cparser_def by force then show "(tsa, ts) \ measure length" by simp qed simp -definition "comment_error = Code.abort (STR ''comment not terminated'') (\ _. '''')" -definition "comment_error_hyphen = Code.abort (STR ''double hyphen within comment'') (\ _. '''')" +definition "comment_error (x :: unit) = Code.abort (STR ''comment not terminated'') (\ _. Nil :: string)" +definition "comment_error_hyphen (x :: unit) = Code.abort (STR ''double hyphen within comment'') (\ _. Nil :: string)" fun rc_aux where "rc_aux False (c # cs) = (if c = CHR ''<'' \ take 3 cs = ''!--'' then rc_aux True (drop 3 cs) else c # rc_aux False cs)" | "rc_aux True (c # cs) = (if c = CHR ''-'' \ take 1 cs = ''-'' then - if take 2 cs = ''-'' then comment_error else if take 2 cs = ''->'' then rc_aux False (drop 2 cs) - else comment_error_hyphen + if take 2 cs = ''-'' then comment_error () else if take 2 cs = ''->'' then rc_aux False (drop 2 cs) + else comment_error_hyphen () else rc_aux True cs)" | "rc_aux False [] = []" | - "rc_aux True [] = comment_error" + "rc_aux True [] = comment_error ()" definition "remove_comments xs = rc_aux False xs" definition "rc_open_1 xs = rc_aux False xs" definition "rc_open_2 xs = rc_aux False (CHR ''<'' # xs)" definition "rc_open_3 xs = rc_aux False (CHR ''<'' # CHR ''!'' # xs)" definition "rc_open_4 xs = rc_aux False (CHR ''<'' # CHR ''!'' # CHR ''-'' # xs)" definition "rc_close_1 xs = rc_aux True xs" definition "rc_close_2 xs = rc_aux True (CHR ''-'' # xs)" definition "rc_close_3 xs = rc_aux True (CHR ''-'' # CHR ''-'' # xs)" lemma remove_comments_code[code]: "remove_comments xs = rc_open_1 xs" unfolding remove_comments_def rc_open_1_def .. lemma char_eq_via_integer_eq: "c = d \ integer_of_char c = integer_of_char d" unfolding integer_of_char_def by simp lemma integer_of_char_simps[simp]: "integer_of_char (CHR ''<'') = 60" "integer_of_char (CHR ''>'') = 62" "integer_of_char (CHR ''/'') = 47" "integer_of_char (CHR ''!'') = 33" "integer_of_char (CHR ''-'') = 45" by code_simp+ lemma rc_open_close_simp[code]: "rc_open_1 (c # cs) = (if integer_of_char c = 60 then rc_open_2 cs else c # rc_open_1 cs)" "rc_open_1 [] = []" "rc_open_2 (c # cs) = (let ic = integer_of_char c in if ic = 33 then rc_open_3 cs else if ic = 60 then c # rc_open_2 cs else CHR ''<'' # c # rc_open_1 cs)" "rc_open_2 [] = ''<''" "rc_open_3 (c # cs) = (let ic = integer_of_char c in if ic = 45 then rc_open_4 cs else if ic = 60 then c # CHR ''!'' # rc_open_2 cs else CHR ''<'' # CHR ''!'' # c # rc_open_1 cs)" "rc_open_3 [] = '' parse_header; xml \ parse_node; eoi; return (XMLDOC h xml) }" definition doc_of_string :: "string \ string + xmldoc" where "doc_of_string s = do { (doc, _) \ parse_doc s; Error_Monad.return doc }" subsection \More efficient code equations\ lemma trim_code[code]: "trim = dropWhile (\ c. let ci = integer_of_char c in if ci \ 34 then False else ci = 32 \ ci = 10 \ ci = 9 \ ci = 13)" unfolding trim_def apply (rule arg_cong[of _ _ dropWhile], rule ext) unfolding Let_def in_set_simps less_eq_char_code char_eq_via_integer_eq by (auto simp: integer_of_char_def Let_def) fun parse_text_main :: "string \ string \ string \ string" where "parse_text_main [] res = ('''', rev (trim res))" | "parse_text_main (c # cs) res = (if c = CHR ''<'' then (c # cs, rev (trim res)) else parse_text_main cs (c # res))" definition "parse_text_impl cs = (case parse_text_main (trim cs) '''' of (rem, txt) \ if txt = [] then Inr (None, rem) else Inr (Some txt, rem))" lemma parse_text_main: "parse_text_main xs ys = (dropWhile ((\) CHR ''<'') xs, rev (trim (rev (takeWhile ((\) CHR ''<'') xs) @ ys)))" by (induct xs arbitrary: ys, auto) lemma many_take_drop: "many f xs = Inr (takeWhile f xs, dropWhile f xs)" by (induct f xs rule: many.induct, auto) lemma trim_takeWhile_inside: "trim (takeWhile ((\) CHR ''<'') cs) = takeWhile ((\) CHR ''<'') (trim cs)" unfolding trim_def by (induct cs, auto) lemma trim_dropWhile_inside: "dropWhile ((\) CHR ''<'') cs = dropWhile ((\) CHR ''<'') (trim cs)" unfolding trim_def by (induct cs, auto) declare [[code drop: parse_text]] lemma parse_text_code[code]: "parse_text cs = parse_text_impl cs" proof - define xs where "xs = trim cs" show ?thesis unfolding parse_text_def unfolding Parser_Monad.bind_def Error_Monad.bind_def unfolding Let_def unfolding many_take_drop sum.simps split unfolding trim_takeWhile_inside trim_dropWhile_inside[of cs] Parser_Monad.return_def unfolding parse_text_impl_def unfolding xs_def[symmetric] unfolding parse_text_main split apply (simp, intro conjI impI, force simp: trim_def) proof define ys where "ys = takeWhile ((\) CHR ''<'') xs" assume "trim (rev (takeWhile ((\) CHR ''<'') xs)) = []" and "takeWhile ((\) CHR ''<'') xs \ []" hence "trim (rev ys) = []" and "ys \ []" unfolding ys_def by auto from this(1) have ys: "\ y. y \ set ys \ y \ set wspace" unfolding trim_def by simp with \ys \ []\ show False unfolding ys_def xs_def trim_def by (metis (no_types, lifting) dropWhile_eq_Nil_conv dropWhile_idem trim_def trim_takeWhile_inside xs_def) qed qed declare [[code drop: parse_text_main]] lemma parse_text_main_code[code]: "parse_text_main [] res = ('''', rev (trim res))" "parse_text_main (c # cs) res = (if integer_of_char c = 60 then (c # cs, rev (trim res)) else parse_text_main cs (c # res))" unfolding parse_text_main.simps by (auto simp: char_eq_via_integer_eq) lemma exactly_head: "exactly [c] (c # cs) = Inr ([c],trim cs)" unfolding exactly_def by simp lemma take_1_test: "(case cs of [] \ False | c # x \ c = CHR ''/'') = (take 1 cs = ''/'')" by (cases cs, auto) definition "exactly_close = exactly ''>''" definition "exactly_end = exactly ''\"'') []" "exactly_close (c # cs) = (if integer_of_char c = 62 then Inr (''>'', trim cs) else err_expecting (''\">\"'') (c # cs))" unfolding exactly_close_def exactly_def exactly_aux.simps by (auto simp: char_eq_via_integer_eq) lemma exactly_end_code[code]: "exactly_end [] = err_expecting (''\" integer_of_char d = 47 then Inr ('' 'a parser \ 'a parser" where "oneof_closed_combined p q (x # xs) = (if x = CHR ''>'' then q (trim xs) else if x = CHR ''/'' \ (case xs of [] \ False | y # ys \ y = CHR ''>'') then p (trim (tl xs)) else err_expecting (''one of [/>, >]'') (x # xs))" | "oneof_closed_combined p q xs = err_expecting (''one of [/>, >]'') xs" lemma oneof_closed_combined: "oneof_closed_combined p q = (oneof_closed \ (\e. if e = ''/>'' then p else q))" (is "?l = ?r") proof (intro ext) fix xs show "?l xs = ?r xs" unfolding Parser_Monad.bind_def Error_Monad.bind_def by (cases xs, auto split: sum.splits simp: err_expecting_def) qed declare [[code drop: oneof_closed_combined]] lemma oneof_closed_combined_code[code]: "oneof_closed_combined p q [] = err_expecting (''one of [/>, >]'') ''''" "oneof_closed_combined p q (x # xs) = (let xi = integer_of_char x in (if xi = 62 then q (trim xs) else (if xi = 47 then (case xs of [] \ err_expecting (''one of [/>, >]'') (x # xs) | y # ys \ if integer_of_char y = 62 then p (trim ys) else err_expecting (''one of [/>, >]'') (x # xs)) else err_expecting (''one of [/>, >]'') (x # xs))))" unfolding oneof_closed_combined.simps Let_def by (auto split: list.splits simp: char_eq_via_integer_eq) lemmas parse_nodes_current_code = parse_nodes.simps[unfolded oneof_closed, unfolded If_removal [of "\ e. e = ''/>''"]] lemma parse_nodes_pre_code: "parse_nodes (c # cs) = (if c = CHR ''<'' then if (case cs of [] \ False | c # _ \ c = CHR ''/'') then Parser_Monad.return [] (c # cs) else (parse_name \ (\n. parse_attributes \ (\atts. oneof_closed_combined (parse_nodes \ (\cs. Parser_Monad.return (XML n atts [] # cs))) (parse_nodes \ (\cs. exactly_end \ (\_. exactly n \ (\_. exactly_close \ (\_. parse_nodes \ (\ns. Parser_Monad.return (XML n atts cs # ns)))))))))) (trim cs) else (parse_text \ (\t. parse_nodes \ (\ns. Parser_Monad.return (XML_text (the t) # ns)))) (c # cs))" unfolding parse_nodes_current_code[of "c # cs"] exactly_close_def exactly_end_def oneof_closed_combined by (simp_all add: Parser_Monad.bind_def exactly_head take_1_test) declare [[code drop: parse_nodes]] lemma parse_nodes_code[code]: "parse_nodes [] = Parser_Monad.return [] ''''" "parse_nodes (c # cs) = (if integer_of_char c = 60 then if (case cs of [] \ False | d # _ \ d = CHR ''/'') then Parser_Monad.return [] (c # cs) else (parse_name \ (\n. parse_attributes \ (\atts. oneof_closed_combined (parse_nodes \ (\cs. Parser_Monad.return (XML n atts [] # cs))) (parse_nodes \ (\cs. exactly_end \ (\_. exactly n \ (\_. exactly_close \ (\_. parse_nodes \ (\ns. Parser_Monad.return (XML n atts cs # ns)))))))))) (trim cs) else (parse_text \ (\t. parse_nodes \ (\ns. Parser_Monad.return (XML_text (the t) # ns)))) (c # cs))" unfolding parse_nodes_pre_code unfolding Let_def by (auto simp: char_eq_via_integer_eq) declare [[code drop: parse_attributes]] lemma parse_attributes_code[code]: "parse_attributes [] = Error_Monad.return ([], [])" "parse_attributes (c # s) = (let ic = integer_of_char c in (if ic = 47 \ ic = 62 then Inr ([], c # s) else (parse_name \ (\k. exactly ''='' \ (\_. parse_attribute_value \ (\v. parse_attributes \ (\atts. Parser_Monad.return ((k, v) # atts)))))) (c # s)))" unfolding parse_attributes.simps unfolding Let_def in_set_simps by (auto simp: char_eq_via_integer_eq) declare [[code drop: is_letter]] lemma is_letter_code[code]: "is_letter c = (let ci = integer_of_char c in (97 \ ci \ ci \ 122 \ 65 \ ci \ ci \ 90 \ 48 \ ci \ ci \ 59 \ ci = 95 \ ci = 38 \ ci = 45))" proof - define d where "d = integer_of_char c" have "d \ 59 \ (d \ 57 \ d = 58 \ d = 59)" for d :: int by auto hence "d \ 59 \ (d \ 57 \ d = 58 \ d = 59)" by (metis int_of_integer_numeral integer_eqI integer_less_eq_iff verit_comp_simplify1(2)) thus ?thesis unfolding is_letter_pre_code in_set_simps Let_def d_def less_eq_char_code char_eq_via_integer_eq unfolding integer_of_char_def by auto qed declare spaces_def[code_unfold del] lemma spaces_code[code]: "spaces cs = Inr ((), trim cs)" unfolding spaces_def trim_def manyof_def many_take_drop Parser_Monad.bind_def Parser_Monad.return_def by auto declare many_letters[code del, code_unfold del] fun many_letters_main where "many_letters_main [] = ([], [])" | "many_letters_main (c # cs) = (if is_letter c then case many_letters_main cs of (ds,es) \ (c # ds, es) else ([], c # cs))" lemma many_letters_code[code]: "many_letters cs = Inr (many_letters_main cs)" unfolding many_letters_def manyof_def many_take_drop by (rule arg_cong[of _ _ Inr], rule sym, induct cs, auto simp: is_letter_def) lemma parse_name_code[code]: "parse_name s = (case many_letters_main s of (n, ts) \ if n = [] then Inl (''expected letter '' @ letters @ '' but first symbol is \"'' @ take 1 s @ ''\"'') else Inr (n, trim ts))" unfolding parse_name_def many_letters_code spaces_code Parser_Monad.bind_def Error_Monad.bind_def sum.simps split Parser_Monad.error_def Parser_Monad.return_def if_distribR by auto end diff --git a/thys/XML/Xmlt.thy b/thys/XML/Xmlt.thy --- a/thys/XML/Xmlt.thy +++ b/thys/XML/Xmlt.thy @@ -1,713 +1,578 @@ -(* Title: Xml - Author: Christian Sternagel - Author: René Thiemann +(* +Author: Akihisa Yamada +Author: Christian Sternagel ( +Author: René Thiemann *) - -section \XML Transformers for Extracting Data from XML Nodes\ - theory Xmlt -imports - Xml - Certification_Monads.Strict_Sum - HOL.Rat + imports + "HOL-Library.Extended_Nat" + Show.Number_Parser + Certification_Monads.Strict_Sum + Show.Shows_Literal + Xml begin -type_synonym - tag = string - -text \The type of transformers on xml nodes.\ -type_synonym - 'a xmlt = "xml \ string +\<^sub>\ 'a" - -definition map :: "(xml \ ('e +\<^sub>\ 'a)) \ xml list \ 'e +\<^sub>\ 'a list" -where - [code_unfold]: "map = map_sum_bot" - -lemma map_mono [partial_function_mono]: - fixes C :: "xml \ ('b \ ('e +\<^sub>\ 'c)) \ 'e +\<^sub>\ 'd" - assumes C: "\y. y \ set B \ mono_sum_bot (C y)" - shows "mono_sum_bot (\f. map (\y. C y f) B)" - unfolding map_def by (auto intro: partial_function_mono C) - -hide_const (open) map - -fun "text" :: "tag \ string xmlt" -where - "text tag (XML n atts [XML_text t]) = - (if n = tag \ atts = [] then return t - else error (concat - [''could not extract text for '', tag,'' from '', ''\'', show (XML n atts [XML_text t])]))" -| "text tag xml = error (concat [''could not extract text for '', tag,'' from '', ''\'', show xml])" -hide_const (open) "text" - -definition bool_of_string :: "string \ string +\<^sub>\ bool" -where - "bool_of_string s = - (if s = ''true'' then return True - else if s = ''false'' then return False - else error (''cannot convert '' @ s @ '' into Boolean''))" - -fun bool :: "tag \ bool xmlt" -where - "bool tag node = Xmlt.text tag node \ bool_of_string" -hide_const (open) bool - -definition fail :: "tag \ 'a xmlt" -where - "fail tag xml = - error (concat - [''could not transform the following xml element (expected '', tag, '')'', ''\'', show xml])" -hide_const (open) fail - -definition guard :: "(xml \ bool) \ 'a xmlt \ 'a xmlt \ 'a xmlt" -where - "guard p p1 p2 x = (if p x then p1 x else p2 x)" -hide_const (open) guard - -lemma guard_mono [partial_function_mono]: - assumes p1: "\y. mono_sum_bot (p1 y)" - and p2: "\y. mono_sum_bot (p2 y)" - shows "mono_sum_bot (\g. Xmlt.guard p (\y. p1 y g) (\y. p2 y g) x)" - by (cases x) (auto intro!: partial_function_mono p1 p2 simp: Xmlt.guard_def) - -fun leaf :: "tag \ 'a \ 'a xmlt" -where - "leaf tag x (XML name atts cs) = - (if name = tag \ atts = [] \ cs = [] then return x - else Xmlt.fail tag (XML name atts cs))" | - "leaf tag x xml = Xmlt.fail tag xml" -hide_const (open) leaf - -fun list1element :: "'a list \ 'a option" -where - "list1element [x] = Some x" | - "list1element _ = None" - -fun singleton :: "tag \ 'a xmlt \ ('a \ 'b) \ 'b xmlt" -where - "singleton tag p1 f xml = - (case xml of - XML name atts cs \ - (if name = tag \ atts = [] then - (case list1element cs of - Some (cs1) \ p1 cs1 \ return \ f - | None \ Xmlt.fail tag xml) - else Xmlt.fail tag xml) - | _ \ Xmlt.fail tag xml)" -hide_const (open) singleton - -lemma singleton_mono [partial_function_mono]: - assumes p: "\y. mono_sum_bot (p1 y)" - shows "mono_sum_bot (\g. Xmlt.singleton t (\y. p1 y g) f x)" - by (cases x, cases "list1element (Xml.children x)") (auto intro!: partial_function_mono p) - -fun list2elements :: "'a list \ ('a \ 'a) option" -where - "list2elements [x, y] = Some (x, y)" | - "list2elements _ = None" - -fun pair :: "tag \ 'a xmlt \ 'b xmlt \ ('a \ 'b \ 'c) \ 'c xmlt" -where - "pair tag p1 p2 f xml = - (case xml of - XML name atts cs \ - (if name = tag \ atts = [] then - (case list2elements cs of - Some (cs1, cs2) \ - do { - a \ p1 cs1; - b \ p2 cs2; - return (f a b) - } - | None \ Xmlt.fail tag xml) - else Xmlt.fail tag xml) - | _ \ Xmlt.fail tag xml)" -hide_const (open) pair - -lemma pair_mono [partial_function_mono]: - assumes "\y. mono_sum_bot (p1 y)" - and "\y. mono_sum_bot (p2 y)" - shows "mono_sum_bot (\g. Xmlt.pair t (\y. p1 y g) (\ y. p2 y g) f x)" - using assms - by (cases x, cases "list2elements (Xml.children x)") (auto intro!: partial_function_mono) - -fun list3elements :: "'a list \ ('a \ 'a \ 'a) option" -where - "list3elements [x, y, z] = Some (x, y, z)" | - "list3elements _ = None" - -fun triple :: "string \ 'a xmlt \ 'b xmlt \ 'c xmlt \ ('a \ 'b \ 'c \ 'd) \ 'd xmlt" -where - "triple tag p1 p2 p3 f xml = (case xml of XML name atts cs \ - (if name = tag \ atts = [] then - (case list3elements cs of - Some (cs1, cs2, cs3) \ - do { - a \ p1 cs1; - b \ p2 cs2; - c \ p3 cs3; - return (f a b c) - } - | None \ Xmlt.fail tag xml) - else Xmlt.fail tag xml) - | _ \ Xmlt.fail tag xml)" - -lemma triple_mono [partial_function_mono]: - assumes "\y. mono_sum_bot (p1 y)" - and "\y. mono_sum_bot (p2 y)" - and "\y. mono_sum_bot (p3 y)" - shows "mono_sum_bot (\g. Xmlt.triple t (\y. p1 y g) (\ y. p2 y g) (\ y. p3 y g) f x)" - using assms - by (cases x, cases "list3elements (Xml.children x)", auto intro!: partial_function_mono) +text \String literals in parser, for nicer generated code\ +type_synonym ltag = String.literal -fun list4elements :: "'a list \ ('a \ 'a \ 'a \ 'a) option" -where - "list4elements [x, y, z, u] = Some (x, y, z, u)" | - "list4elements _ = None" - -fun - tuple4 :: - "string \ 'a xmlt \ 'b xmlt \ 'c xmlt \ 'd xmlt \ ('a \ 'b \ 'c \ 'd \ 'e) \ 'e xmlt" -where - "tuple4 tag p1 p2 p3 p4 f xml = - (case xml of - XML name atts cs \ - (if name = tag \ atts = [] then - (case list4elements cs of - Some (cs1, cs2, cs3, cs4) \ - do { - a \ p1 cs1; - b \ p2 cs2; - c \ p3 cs3; - d \ p4 cs4; - return (f a b c d) - } - | None \ Xmlt.fail tag xml) - else Xmlt.fail tag xml) - | _ \ Xmlt.fail tag xml)" - -lemma tuple4_mono [partial_function_mono]: - assumes "\y. mono_sum_bot (p1 y)" - and "\y. mono_sum_bot (p2 y)" - and "\y. mono_sum_bot (p3 y)" - and"\y. mono_sum_bot (p4 y)" - shows "mono_sum_bot (\g. Xmlt.tuple4 t (\y. p1 y g) (\ y. p2 y g) (\ y. p3 y g) (\ y. p4 y g) f x)" - using assms - by (cases x, cases "list4elements (Xml.children x)") (auto intro!: partial_function_mono) - -fun list5elements :: "'a list \ ('a \ 'a \ 'a \ 'a \ 'a) option" -where - "list5elements [x, y, z, u, v] = Some (x, y, z, u, v)" | - "list5elements _ = None" - -fun - tuple5 :: - "string \ 'a xmlt \ 'b xmlt \ 'c xmlt \ 'd xmlt \ 'e xmlt \ - ('a \ 'b \ 'c \ 'd \ 'e \ 'f) \ 'f xmlt" -where - "tuple5 tag p1 p2 p3 p4 p5 f xml = - (case xml of - XML name atts cs \ - (if name = tag \ atts = [] then - (case list5elements cs of - Some (cs1,cs2,cs3,cs4,cs5) \ - do { - a \ p1 cs1; - b \ p2 cs2; - c \ p3 cs3; - d \ p4 cs4; - e \ p5 cs5; - return (f a b c d e) - } - | None \ Xmlt.fail tag xml) - else Xmlt.fail tag xml) - | _ \ Xmlt.fail tag xml)" - -lemma tuple5_mono [partial_function_mono]: - assumes "\y. mono_sum_bot (p1 y)" - and "\y. mono_sum_bot (p2 y)" - and "\y. mono_sum_bot (p3 y)" - and "\y. mono_sum_bot (p4 y)" - and "\y. mono_sum_bot (p5 y)" - shows "mono_sum_bot (\g. Xmlt.tuple5 t (\y. p1 y g) (\ y. p2 y g) (\ y. p3 y g) (\ y. p4 y g) (\ y. p5 y g) f x)" - using assms - by (cases x, cases "list5elements (Xml.children x)") (auto intro!: partial_function_mono) +datatype 'a xml_error = TagMismatch "ltag list" | Fatal 'a +text \ + @{term "TagMismatch tags"} represents tag mismatch, expecting one of @{term tags} but + something else is encountered. +\ -fun list6elements :: "'a list \ ('a \ 'a \ 'a \ 'a \ 'a \ 'a) option" -where - "list6elements [x, y, z, u, v, w] = Some (x, y, z, u, v, w)" | - "list6elements _ = None" - -fun - tuple6 :: - "string \ 'a xmlt \ 'b xmlt \ 'c xmlt \ 'd xmlt \ 'e xmlt \ 'f xmlt \ - ('a \ 'b \ 'c \ 'd \ 'e \ 'f \ 'g) \ 'g xmlt" -where - "tuple6 tag p1 p2 p3 p4 p5 p6 f xml = - (case xml of - XML name atts cs \ - (if name = tag \ atts = [] then - (case list6elements cs of - Some (cs1,cs2,cs3,cs4,cs5,cs6) \ - do { - a \ p1 cs1; - b \ p2 cs2; - c \ p3 cs3; - d \ p4 cs4; - e \ p5 cs5; - ff \ p6 cs6; - return (f a b c d e ff) - } - | None \ Xmlt.fail tag xml) - else Xmlt.fail tag xml) - | _ \ Xmlt.fail tag xml)" +lemma xml_error_mono [partial_function_mono]: + assumes p1: "\tags. mono_option (p1 tags)" + and p2: "\x. mono_option (p2 x)" + and f: "mono_option f" + shows "mono_option (\g. case s of TagMismatch tags \ p1 tags g | Fatal x \ p2 x g)" + using assms by (cases s, auto intro!:partial_function_mono) -lemma tuple6_mono [partial_function_mono]: - assumes "\y. mono_sum_bot (p1 y)" - and "\y. mono_sum_bot (p2 y)" - and "\y. mono_sum_bot (p3 y)" - and "\y. mono_sum_bot (p4 y)" - and "\y. mono_sum_bot (p5 y)" - and "\y. mono_sum_bot (p6 y)" - shows "mono_sum_bot (\g. Xmlt.tuple6 t (\y. p1 y g) (\ y. p2 y g) (\ y. p3 y g) (\ y. p4 y g) (\ y. p5 y g) (\ y. p6 y g) f x)" - using assms - by (cases x, cases "list6elements (Xml.children x)") (auto intro!: partial_function_mono) - -fun optional :: "tag \ 'a xmlt \ ('a option \ 'b) \ 'b xmlt" -where - "optional tag p1 f (XML name atts cs) = - (let l = length cs in - (if name = tag \ atts = [] \ l \ 0 \ l \ 1 then do { - if l = 1 then do { - x1 \ p1 (cs ! 0); - return (f (Some x1)) - } else return (f None) - } else Xmlt.fail tag (XML name atts cs)))" | - "optional tag p1 f xml = Xmlt.fail tag xml" +text \A state is a tuple of + the XML or list of XMLs to be parsed, + the attributes, + a flag indicating if mismatch is allowed, + a list of tags that have been mismatched, + the current position. +\ +type_synonym 'a xmlt = "xml \ (string \ string) list \ bool \ ltag list \ ltag list \ String.literal xml_error +\<^sub>\ 'a" +type_synonym 'a xmlst = "xml list \ (string \ string) list \ bool \ ltag list \ ltag list \ String.literal xml_error +\<^sub>\ 'a" -lemma optional_mono [partial_function_mono]: - assumes "\y. mono_sum_bot (p1 y)" - shows "mono_sum_bot (\g. Xmlt.optional t (\y. p1 y g) f x)" - using assms by (cases x) (auto intro!: partial_function_mono) +lemma xml_state_cases: + assumes "\p nam atts xmls. x = (XML nam atts xmls, p) \ thesis" + and "\p txt. x = (XML_text txt, p) \ thesis" + shows thesis + using assms by (cases x; cases "fst x", auto) -fun xml1to2elements :: "string \ 'a xmlt \ 'b xmlt \ ('a \ 'b option \ 'c) \ 'c xmlt" -where - "xml1to2elements tag p1 p2 f (XML name atts cs) = ( - let l = length cs in - (if name = tag \ atts = [] \ l \ 1 \ l \ 2 - then do { - x1 \ p1 (cs ! 0); - (if l = 2 - then do { - x2 \ p2 (cs ! 1); - return (f x1 (Some x2)) - } else return (f x1 None)) - } else Xmlt.fail tag (XML name atts cs)))" | - "xml1to2elements tag p1 p2 f xml = Xmlt.fail tag xml" +lemma xmls_state_cases: + assumes "\p. x = ([],p) \ thesis" + and "\xml xmls p. x = (xml # xmls, p) \ thesis" + shows thesis + using assms by (cases x; cases "fst x", auto) -lemma xml1to2elements_mono[partial_function_mono]: - assumes p1: "\y. mono_sum_bot (p1 y)" - "\y. mono_sum_bot (p2 y)" - shows "mono_sum_bot (\g. xml1to2elements t (\y. p1 y g) (\y. p2 y g) f x)" - by (cases x, auto intro!: partial_function_mono p1) +lemma xmls_state_induct: + fixes x :: "xml list \ _" + assumes "\a b c d. P ([],a,b,c,d)" + and "\xml xmls a b c d. (\a b c d. P (xmls,a,b,c,d)) \ P (xml # xmls, a, b, c, d)" + shows "P x" +proof (induct x) + case (fields xmls a b c d) + with assms show ?case by (induct xmls arbitrary:a b c d, auto) +qed + +definition xml_error + where "xml_error str x \ case x of (xmls,_,_,_,pos) \ + let next = case xmls of + XML tag _ _ # _ \ STR ''<'' + String.implode tag + STR ''>'' + | XML_text str # _ \ STR ''text element \"'' + String.implode str + STR ''\"'' + | [] \ STR ''tag close'' + in + Left (Fatal (STR ''parse error on '' + next + STR '' at '' + default_showsl_list showsl_lit pos (STR '''') + STR '':\'' + str))" + +definition xml_return :: "'a \ 'a xmlst" + where "xml_return v x \ case x + of ([],_) \ Right v + | _ \ xml_error (STR ''expecting tag close'') x" + +definition "mismatch tag x \ case x of + (xmls,atts,flag,cands,_) \ + if flag then Left (TagMismatch (tag#cands)) + else xml_error (STR ''expecting '' + default_showsl_list showsl_lit (tag#cands) (STR '''')) x" + +abbreviation xml_any :: "xml xmlt" + where + "xml_any x \ Right (fst x)" + +text \Conditional parsing depending on tag match.\ + +definition bind2 :: "'a +\<^sub>\'b \ ('a \ 'c +\<^sub>\ 'd) \ ('b \ 'c +\<^sub>\ 'd) \ 'c +\<^sub>\ 'd" where + "bind2 x f g = (case x of + Bottom \ Bottom + | Left a \ f a + | Right b \ g b)" + +lemma bind2_cong[fundef_cong]: "x = y \ (\ a. y = Left a \ f1 a = f2 a) \ + (\ b. y = Right b \ g1 b = g2 b) \ bind2 x f1 g1 = bind2 y f2 g2" + by (cases x, auto simp: bind2_def) + +lemma bind2_code[code]: + "bind2 (sumbot a) f g = (case a of Inl a \ f a | Inr b \ g b)" + by (cases a) (auto simp: bind2_def) + +definition xml_or (infixr "XMLor" 51) + where + "xml_or p1 p2 x \ case x of (x1,atts,flag,cands,rest) \ ( + bind2 (p1 (x1,atts,True,cands,rest)) + (\ err1. case err1 + of TagMismatch cands1 \ p2 (x1,atts,flag,cands1,rest) + | err1 \ Left err1) + Right)" + +definition xml_do :: "ltag \ 'a xmlst \ 'a xmlt" where + "xml_do tag p x \ + case x of (XML nam atts xmls, _, flag, cands, pos) \ + if nam = String.explode tag then p (xmls,atts,False,[],tag#pos) \ \inner tag mismatch is not allowed\ + else mismatch tag ([fst x], snd x) + | _ \ mismatch tag ([fst x], snd x)" + +text \parses the first child\ +definition xml_take :: "'a xmlt \ ('a \ 'b xmlst) \ 'b xmlst" + where "xml_take p1 p2 x \ + case x of ([],rest) \ ( + \ \Only for accumulating expected tags.\ + bind2 (p1 (XML [] [] [], rest)) Left (\ a. Left (Fatal (STR ''unexpected''))) + ) + | (x#xs,atts,flag,cands,rest) \ ( + bind2 (p1 (x,atts,flag,cands,rest)) Left + (\ a. p2 a (xs,atts,False,[],rest))) \ \If one child is parsed, then later mismatch is not allowed\" + +definition xml_take_text :: "(string \ 'a xmlst) \ 'a xmlst" where + "xml_take_text p xs \ + case xs of (XML_text text # xmls, s) \ p text (xmls,s) + | _ \ xml_error (STR ''expecting a text'') xs" + +definition xml_take_int :: "(int \ 'a xmlst) \ 'a xmlst" where + "xml_take_int p xs \ + case xs of (XML_text text # xmls, s) \ + (case int_of_string text of Inl x \ xml_error x xs | Inr n \ p n (xmls,s)) + | _ \ xml_error (STR ''expecting an integer'') xs" + +definition xml_take_nat :: "(nat \ 'a xmlst) \ 'a xmlst" where + "xml_take_nat p xs \ + case xs of (XML_text text # xmls, s) \ + (case nat_of_string text of Inl x \ xml_error x xs | Inr n \ p n (xmls,s)) + | _ \ xml_error (STR ''expecting a number'') xs" + +definition xml_leaf where + "xml_leaf tag ret \ xml_do tag (xml_return ret)" + +definition xml_text :: "ltag \ string xmlt" where + "xml_text tag \ xml_do tag (xml_take_text xml_return)" + +definition xml_int :: "ltag \ int xmlt" where + "xml_int tag \ xml_do tag (xml_take_int xml_return)" + +definition xml_nat :: "ltag \ nat xmlt" where + "xml_nat tag \ xml_do tag (xml_take_nat xml_return)" + +definition bool_of_string :: "string \ String.literal + bool" + where + "bool_of_string s \ + if s = ''true'' then Inr True + else if s = ''false'' then Inr False + else Inl (STR ''cannot convert \"'' + String.implode s + STR ''\" into Boolean'')" + +definition xml_bool :: "ltag \ bool xmlt" + where + "xml_bool tag x \ + bind2 (xml_text tag x) Left + (\ str. ( case bool_of_string str of Inr b \ Right b + | Inl err \ xml_error err ([fst x], snd x) + ))" + + +definition xml_change :: "'a xmlt \ ('a \ 'b xmlst) \ 'b xmlt" where + "xml_change p f x \ + bind2 (p x) Left (\ a. case x of (_,rest) \ f a ([],rest))" + text \ - Apply the first transformer to the first child-node, then check the second child-node, - which is must be a Boolean. If the Boolean is true, then apply the second transformer - to the last child-node. + Parses the first child, if tag matches. \ -fun xml2nd_choice :: "tag \ 'a xmlt \ tag \ 'b xmlt \ ('a \ 'b option \ 'c) \ 'c xmlt" -where - "xml2nd_choice tag p1 cn p2 f (XML name atts cs) = ( - let l = length cs in - (if name = tag \ atts = [] \ l \ 2 then do { - x1 \ p1 (cs ! 0); - b \ Xmlt.bool cn (cs ! 1); - (if b then do { - x2 \ p2 (cs ! (l - 1)); - return (f x1 (Some x2)) - } else return (f x1 None)) - } else Xmlt.fail tag (XML name atts cs)))" | - "xml2nd_choice tag p1 cn p2 f xml = Xmlt.fail tag xml" - -lemma xml2nd_choice_mono [partial_function_mono]: - assumes p1: "\y. mono_sum_bot (p1 y)" - "\y. mono_sum_bot (p2 y)" - shows "mono_sum_bot (\g. xml2nd_choice t (\y. p1 y g) h (\y. p2 y g) f x)" - by (cases x, auto intro!: partial_function_mono p1) - -fun - xml2to3elements :: - "string \ 'a xmlt \ 'b xmlt \ 'c xmlt \ ('a \ 'b \ 'c option \ 'd) \ 'd xmlt" -where - "xml2to3elements tag p1 p2 p3 f (XML name atts cs) = ( - let l = length cs in - (if name = tag \ atts = [] \ l \ 2 \ l \ 3 then do { - x1 \ p1 (cs ! 0); - x2 \ p2 (cs ! 1); - (if l = 3 then do { - x3 \ p3 (cs ! 2); - return (f x1 x2 (Some x3)) - } else return (f x1 x2 None)) - } else Xmlt.fail tag (XML name atts cs)))" | - "xml2to3elements tag p1 p2 p3 f xml = Xmlt.fail tag xml" - -lemma xml2to3elements_mono [partial_function_mono]: - assumes p1: "\y. mono_sum_bot (p1 y)" - "\y. mono_sum_bot (p2 y)" - "\y. mono_sum_bot (p3 y)" - shows "mono_sum_bot (\g. xml2to3elements t (\y. p1 y g) (\y. p2 y g) (\y. p3 y g) f x)" - by (cases x, auto intro!: partial_function_mono p1) - -fun - xml3to4elements :: - "string \ 'a xmlt \ 'b xmlt \ 'c xmlt \ 'd xmlt \ ('a \ 'b \ 'c option \ 'd \ 'e) \ - 'e xmlt" -where - "xml3to4elements tag p1 p2 p3 p4 f (XML name atts cs) = ( - let l = length cs in - (if name = tag \ atts = [] \ l \ 3 \ l \ 4 then do { - x1 \ p1 (cs ! 0); - x2 \ p2 (cs ! 1); - (if l = 4 then do { - x3 \ p3 (cs ! 2); - x4 \ p4 (cs ! 3); - return (f x1 x2 (Some x3) x4) - } else do { - x4 \ p4 (cs ! 2); - return (f x1 x2 None x4) - } ) - } else Xmlt.fail tag (XML name atts cs)))" | - "xml3to4elements tag p1 p2 p3 p4 f xml = Xmlt.fail tag xml" - -lemma xml3to4elements_mono [partial_function_mono]: - assumes p1: "\y. mono_sum_bot (p1 y)" - "\y. mono_sum_bot (p2 y)" - "\y. mono_sum_bot (p3 y)" - "\y. mono_sum_bot (p4 y)" - shows "mono_sum_bot (\g. xml3to4elements t (\y. p1 y g) (\y. p2 y g) (\y. p3 y g) (\y. p4 y g) f x)" - by (cases x, auto intro!: partial_function_mono p1) - -fun many :: "tag \ 'a xmlt \ ('a list \ 'b) \ 'b xmlt" -where - "many tag p f (XML name atts cs) = - (if name = tag \ atts = [] then (Xmlt.map p cs \ (return \ f)) - else Xmlt.fail tag (XML name atts cs))" | - "many tag p f xml = Xmlt.fail tag xml" -hide_const (open) many - -lemma many_mono [partial_function_mono]: - fixes p1 :: "xml \ ('b \ (string +\<^sub>\ 'c)) \ string +\<^sub>\ 'd" - assumes "\y. y \ set (Xml.children x) \ mono_sum_bot (p1 y)" - shows "mono_sum_bot (\g. Xmlt.many t (\y. p1 y g) f x)" - using assms by (cases x) (auto intro!: partial_function_mono) - -fun many1_gen :: "tag \ 'a xmlt \ ('a \ 'b xmlt) \ ('a \ 'b list \ 'c) \ 'c xmlt" -where - "many1_gen tag p1 p2 f (XML name atts cs) = - (if name = tag \ atts = [] \ cs \ [] then - (case cs of h # t \ do { - x \ p1 h; - xs \ Xmlt.map (p2 x) t; - return (f x xs) - }) - else Xmlt.fail tag (XML name atts cs))" | - "many1_gen tag p1 p2 f xml = Xmlt.fail tag xml" - -(* TODO -lemma Xmlt.many1_gen_mono[partial_function_mono]: - fixes p1 :: "xml \ ('b \ 'c sum_bot) \ 'd sum_bot" - assumes p1: "\y. mono_sum_bot (p1 y)" - "\y. mono_sum_bot (p2 y)" - shows "mono_sum_bot (\g. Xmlt.many1_gen t (\y. p1 y g) (\y. p2 y g) f x)" - by (cases x, auto intro!: partial_function_mono p1) -*) - -definition many1 :: "string \ 'a xmlt \ 'b xmlt \ ('a \ 'b list \ 'c) \ 'c xmlt" -where - "many1 tag p1 p2 = Xmlt.many1_gen tag p1 (\_. p2)" -hide_const (open) many1 - -lemma many1_mono [partial_function_mono]: - fixes p1 :: "xml \ ('b \ (string +\<^sub>\ 'c)) \ string +\<^sub>\ 'd" - assumes "\y. mono_sum_bot (p1 y)" - and "\y. y \ set (tl (Xml.children x)) \ mono_sum_bot (p2 y)" - shows "mono_sum_bot (\g. Xmlt.many1 t (\y. p1 y g) (\y. p2 y g) f x)" - unfolding Xmlt.many1_def using assms - by (cases x, cases "Xml.children x") (auto intro!: partial_function_mono) - -fun length_ge_2 :: "'a list \ bool" -where - "length_ge_2 (_ # _ # _) = True" | - "length_ge_2 _ = False" +definition xml_take_optional :: "'a xmlt \ ('a option \ 'b xmlst) \ 'b xmlst" + where "xml_take_optional p1 p2 xs \ + case xs of ([],_) \ p2 None xs + | (xml # xmls, atts, allow, cands, rest) \ + bind2 (p1 (xml, atts, True, cands, rest)) + (\ e. case e of + TagMismatch cands1 \ p2 None (xml#xmls, atts, allow, cands1, rest) \ \TagMismatch is allowed\ + | _ \ Left e) + (\ a. p2 (Some a) (xmls, atts, False, [], rest))" -fun many2 :: "tag \ 'a xmlt \ 'b xmlt \ 'c xmlt \ ('a \ 'b \ 'c list \ 'd) \ 'd xmlt" -where - "many2 tag p1 p2 p3 f (XML name atts cs) = - (if name = tag \ atts = [] \ length_ge_2 cs then - (case cs of cs0 # cs1 # t \ do { - x \ p1 cs0; - y \ p2 cs1; - xs \ Xmlt.map p3 t; - return (f x y xs) - }) - else Xmlt.fail tag (XML name atts cs))" | - "many2 tag p1 p2 p3 f xml = Xmlt.fail tag xml" - -lemma many2_mono [partial_function_mono]: - fixes p1 :: "xml \ ('b \ (string +\<^sub>\ 'c)) \ string +\<^sub>\ 'd" - assumes "\y. mono_sum_bot (p1 y)" - and "\y. mono_sum_bot (p2 y)" - and "\y. mono_sum_bot (p3 y)" - shows "mono_sum_bot (\g. Xmlt.many2 t (\y. p1 y g) (\y. p2 y g) (\y. p3 y g) f x)" - using assms - by (cases x, cases "Xml.children x", (auto intro!: partial_function_mono)[1], cases "tl (Xml.children x)", auto intro!: partial_function_mono) - -fun - xml1or2many_elements :: - "string \ 'a xmlt \ 'b xmlt \ 'c xmlt \ ('a \ 'b option \ 'c list \ 'd) \ 'd xmlt" -where - "xml1or2many_elements tag p1 p2 p3 f (XML name atts cs) = - (if name = tag \ atts = [] \ cs \ [] then - (case cs of - cs0 # tt \ - do { - x \ p1 cs0; - (case tt of - cs1 # t \ - do { - try do { - y \ p2 cs1; - xs \ Xmlt.map p3 t; - return (f x (Some y) xs) - } catch (\ _. do { - xs \ Xmlt.map p3 tt; - return (f x None xs) - }) - } - | [] \ return (f x None []))}) - else Xmlt.fail tag (XML name atts cs))" | - "xml1or2many_elements tag p1 p2 p3 f xml = Xmlt.fail tag xml" - -fun - xml1many2elements_gen :: - "string \ 'a xmlt \ ('a \ 'b xmlt) \ 'c xmlt \ 'd xmlt \ - ('a \ 'b list \ 'c \ 'd \ 'e) \ 'e xmlt" -where - "xml1many2elements_gen tag p1 p2 p3 p4 f (XML name atts cs) = ( - let ds = List.rev cs; l = length cs in - (if name = tag \ atts = [] \ l \ 3 then do { - x \ p1 (cs ! 0); - xs \ Xmlt.map (p2 x) (tl (take (l - 2) cs)); - y \ p3 (ds ! 1); - z \ p4 (ds ! 0); - return (f x xs y z) - } else Xmlt.fail tag (XML name atts cs)))" | - "xml1many2elements_gen tag p1 p2 p3 p4 f xml = Xmlt.fail tag xml" +definition xml_take_default :: "'a \ 'a xmlt \ ('a \ 'b xmlst) \ 'b xmlst" + where "xml_take_default a p1 p2 xs \ + case xs of ([],_) \ p2 a xs + | (xml # xmls, atts, allow, cands, rest) \ ( + bind2 (p1 (xml, atts, True, cands, rest)) + (\ e. case e of + TagMismatch cands1 \ p2 a (xml#xmls, atts, allow, cands1, rest) \ \TagMismatch is allowed\ + | _ \ Left e) + (\a. p2 a (xmls, atts, False, [], rest)))" -lemma xml1many2elements_gen_mono [partial_function_mono]: - fixes p1 :: "xml \ ('b \ (string +\<^sub>\ 'c)) \ string +\<^sub>\ 'd" - assumes p1: "\y. mono_sum_bot (p1 y)" - "\y. mono_sum_bot (p3 y)" - "\y. mono_sum_bot (p4 y)" - shows "mono_sum_bot (\g. xml1many2elements_gen t (\y. p1 y g) p2 (\y. p3 y g) (\y. p4 y g) f x)" - by (cases x, auto intro!: partial_function_mono p1) - -fun - xml1many2elements :: - "string \ 'a xmlt \ 'b xmlt \ 'c xmlt \ 'd xmlt \ ('a \ 'b list \ 'c \ 'd \ 'e) \ - 'e xmlt" -where - "xml1many2elements tag p1 p2 = xml1many2elements_gen tag p1 (\_. p2)" - -fun - xml_many2elements :: - "string \ 'a xmlt \ 'b xmlt \ 'c xmlt \ ('a list \ 'b \ 'c \ 'd) \ 'd xmlt" -where - "xml_many2elements tag p1 p2 p3 f (XML name atts cs) = ( - let ds = List.rev cs in - (if name = tag \ atts = [] \ length_ge_2 cs then do { - xs \ Xmlt.map p1 (List.rev (tl (tl ds))); - y \ p2 (ds ! 1); - z \ p3 (ds ! 0); - return (f xs y z) - } else Xmlt.fail tag (XML name atts cs)))" | - "xml_many2elements tag p1 p2 p3 f xml = Xmlt.fail tag xml" - -definition options :: "(string \ 'a xmlt) list \ 'a xmlt" -where - "options ps x = - (case map_of ps (Xml.tag x) of - None \ error (concat - [''expected one of: '', concat (map (\p. fst p @ '' '') ps), ''\'', ''but found'', ''\'', show x]) - | Some p \ p x)" -hide_const (open) options +text \Take first children, as many as tag matches.\ -lemma options_mono_gen [partial_function_mono]: - assumes p: "\ k p. (k, p) \ set ps \ mono_sum_bot (p x)" - shows "mono_sum_bot (\ g. Xmlt.options (map (\ (k, p). (k, (\ y. p y g))) ps) x)" -proof - - { - fix g - have "(map (\p. fst p @ '' '') (map (\(k, p). (k, \y. p y g)) ps)) = - map (\p. fst p @ '' '') ps" - by (induct ps) (auto) - } note id = this - { - fix z - have "mono_sum_bot - (\g. case map_of (map (\(k, p). (k, \y. p y g)) ps) (Xml.tag x) of - None \ z - | Some p \ p x)" - using p - proof (induct ps) - case Nil - show ?case by (auto intro: partial_function_mono) - next - case (Cons kp ps) - obtain k p where kp: "kp = (k,p)" by force - note Cons = Cons[unfolded kp] - from Cons(2) have monop: "mono_sum_bot (p x)" and mono: "\ k p. (k,p) \ set ps \ mono_sum_bot (p x)" by auto - show ?case - proof (cases "Xml.tag x = k") - case True - thus ?thesis unfolding kp using monop by auto - next - case False - thus ?thesis using Cons(1) mono unfolding kp by auto - qed - qed - } note main = this - show ?thesis unfolding Xmlt.options_def - unfolding id - by (rule main) +fun xml_take_many_sub :: "'a list \ nat \ enat \ 'a xmlt \ ('a list \ 'b xmlst) \ 'b xmlst" where + "xml_take_many_sub acc minOccurs maxOccurs p1 p2 ([], atts, allow, rest) = ( + if minOccurs = 0 then p2 (rev acc) ([], atts, allow, rest) + else \ \only for nice error log\ + bind2 (p1 (XML [] [] [], atts, False, rest)) Left (\ _. Left (Fatal (STR ''unexpected''))) + )" +| "xml_take_many_sub acc minOccurs maxOccurs p1 p2 (xml # xmls, atts, allow, cands, rest) = ( + if maxOccurs = 0 then p2 (rev acc) (xml # xmls, atts, allow, cands, rest) + else + bind2 (p1 (xml, atts, minOccurs = 0, cands, rest)) + (\ e. case e of + TagMismatch tags \ p2 (rev acc) (xml # xmls, atts, allow, cands, rest) + | _ \ Left e) + (\ a. xml_take_many_sub (a # acc) (minOccurs-1) (maxOccurs-1) p1 p2 (xmls, atts, False, [], rest)) + )" + +abbreviation xml_take_many where "xml_take_many \ xml_take_many_sub []" + +fun pick_up where + "pick_up rest key [] = None" +| "pick_up rest key ((l,r)#s) = (if key = l then Some (r,rest@s) else pick_up ((l,r)#rest) key s)" + +definition xml_take_attribute :: "ltag \ (string \ 'a xmlst) \ 'a xmlst" + where "xml_take_attribute att p xs \ + case xs of (xmls,atts,allow,cands,pos) \ ( + case pick_up [] (String.explode att) atts of + None \ xml_error (STR ''attribute \"'' + att + STR ''\" not found'') xs + | Some(v,rest) \ p v (xmls,rest,allow,cands,pos) + )" + +definition xml_take_attribute_optional :: "ltag \ (string option \ 'a xmlst) \ 'a xmlst" + where "xml_take_attribute_optional att p xs \ + case xs of (xmls,atts,info) \ ( + case pick_up [] (String.explode att) atts of + None \ p None xs + | Some(v,rest) \ p (Some v) (xmls,rest,info) + )" + +definition xml_take_attribute_default :: "string \ ltag \ (string \ 'a xmlst) \ 'a xmlst" + where "xml_take_attribute_default def att p xs \ + case xs of (xmls,atts,info) \ ( + case pick_up [] (String.explode att) atts of + None \ p def xs + | Some(v,rest) \ p v (xmls,rest,info) + )" + +nonterminal xml_binds and xml_bind +syntax + "_xml_block" :: "xml_binds \ 'a" ("XMLdo {//(2 _)//}" [12] 1000) + "_xml_take" :: "pttrn \ 'a \ xml_bind" ("(2_ \/ _)" 13) + "_xml_take_text" :: "pttrn \ xml_bind" ("(2_ \text)" 13) + "_xml_take_int" :: "pttrn \ xml_bind" ("(2_ \int)" 13) + "_xml_take_nat" :: "pttrn \ xml_bind" ("(2_ \nat)" 13) + "_xml_take_att" :: "pttrn \ ltag \ xml_bind" ("(2_ \att/ _)" 13) + "_xml_take_att_optional" :: "pttrn \ ltag \ xml_bind" ("(2_ \att?/ _)" 13) + "_xml_take_att_default" :: "pttrn \ ltag \ string \ xml_bind" ("(2_ \att[(_)]/ _)" 13) + "_xml_take_optional" :: "pttrn \ 'a \ xml_bind" ("(2_ \?/ _)" 13) + "_xml_take_default" :: "pttrn \ 'b \ 'a \ xml_bind" ("(2_ \[(_)]/ _)" 13) + "_xml_take_all" :: "pttrn \ 'a \ xml_bind" ("(2_ \*/ _)" 13) + "_xml_take_many" :: "pttrn \ nat \ enat \ 'a \ xml_bind" ("(2_ \^{(_)..(_)}/ _)" 13) + "_xml_let" :: "pttrn \ 'a \ xml_bind" ("(2let _ =/ _)" [1000, 13] 13) + "_xml_final" :: "'a xmlst \ xml_binds" ("_") + "_xml_cons" :: "xml_bind \ xml_binds \ xml_binds" ("_;//_" [13, 12] 12) + "_xml_do" :: "ltag \ xml_binds \ 'a" ("XMLdo (_) {//(2 _)//}" [1000,12] 1000) + +syntax (ASCII) + "_xml_take" :: "pttrn \ 'a \ xml_bind" ("(2_ <-/ _)" 13) + +translations + "_xml_block (_xml_cons (_xml_take p x) (_xml_final e))" + \ "_xml_block (_xml_final (CONST xml_take x (\p. e)))" + "_xml_block (_xml_cons (_xml_take_text p) (_xml_final e))" + \ "_xml_block (_xml_final (CONST xml_take_text (\p. e)))" + "_xml_block (_xml_cons (_xml_take_int p) (_xml_final e))" + \ "_xml_block (_xml_final (CONST xml_take_int (\p. e)))" + "_xml_block (_xml_cons (_xml_take_nat p) (_xml_final e))" + \ "_xml_block (_xml_final (CONST xml_take_nat (\p. e)))" + "_xml_block (_xml_cons (_xml_take_att p x) (_xml_final e))" + \ "_xml_block (_xml_final (CONST xml_take_attribute x (\p. e)))" + "_xml_block (_xml_cons (_xml_take_att_optional p x) (_xml_final e))" + \ "_xml_block (_xml_final (CONST xml_take_attribute_optional x (\p. e)))" + "_xml_block (_xml_cons (_xml_take_att_default p d x) (_xml_final e))" + \ "_xml_block (_xml_final (CONST xml_take_attribute_default d x (\p. e)))" + "_xml_block (_xml_cons (_xml_take_optional p x) (_xml_final e))" + \ "_xml_block (_xml_final (CONST xml_take_optional x (\p. e)))" + "_xml_block (_xml_cons (_xml_take_default p d x) (_xml_final e))" + \ "_xml_block (_xml_final (CONST xml_take_default d x (\p. e)))" + "_xml_block (_xml_cons (_xml_take_all p x) (_xml_final e))" + \ "_xml_block (_xml_final (CONST xml_take_many 0 \ x (\p. e)))" + "_xml_block (_xml_cons (_xml_take_many p minOccurs maxOccurs x) (_xml_final e))" + \ "_xml_block (_xml_final (CONST xml_take_many minOccurs maxOccurs x (\p. e)))" + "_xml_block (_xml_cons (_xml_let p t) bs)" + \ "let p = t in _xml_block bs" + "_xml_block (_xml_cons b (_xml_cons c cs))" + \ "_xml_block (_xml_cons b (_xml_final (_xml_block (_xml_cons c cs))))" + "_xml_cons (_xml_let p t) (_xml_final s)" + \ "_xml_final (let p = t in s)" + "_xml_block (_xml_final e)" \ "e" + "_xml_do t e" \ "CONST xml_do t (_xml_block e)" + +fun xml_error_to_string where + "xml_error_to_string (Fatal e) = String.explode (STR ''Fatal: '' + e)" +| "xml_error_to_string (TagMismatch e) = String.explode (STR ''tag mismatch: '' + default_showsl_list showsl_lit e (STR ''''))" + +definition parse_xml :: "'a xmlt \ xml \ string +\<^sub>\ 'a" + where "parse_xml p xml \ + bind2 (xml_take p xml_return ([xml],[],False,[],[])) + (Left o xml_error_to_string) Right" + +(*BEGIN: special chars*) +subsection \Handling of special characters in text\ + +definition "special_map = map_of [ + (''quot'', ''\"''), (''#34'', ''\"''), \ \double quotation mark\ + (''amp'', ''&''), (''#38'', ''&''), \ \ampersand\ + (''apos'', [CHR 0x27]), (''#39'', [CHR 0x27]), \ \single quotes\ + (''lt'', ''<''), (''#60'', ''<''), \ \less-than sign\ + (''gt'', ''>''), (''#62'', ''>'') \ \greater-than sign\ +]" + +fun extract_special + where + "extract_special acc [] = None" + | "extract_special acc (x # xs) = + (if x = CHR '';'' then map_option (\s. (s, xs)) (special_map (rev acc)) + else extract_special (x#acc) xs)" + +lemma extract_special_length [termination_simp]: + assumes "extract_special acc xs = Some (y, ys)" + shows "length ys < length xs" + using assms by (induct acc xs rule: extract_special.induct) (auto split: if_splits) + +fun normalize_special + where + "normalize_special [] = []" + | "normalize_special (x # xs) = + (if x = CHR ''&'' then + (case extract_special [] xs of + None \ ''&'' @ normalize_special xs + | Some (spec, ys) \ spec @ normalize_special ys) + else x # normalize_special xs)" + +fun map_xml_text :: "(string \ string) \ xml \ xml" + where + "map_xml_text f (XML t as cs) = XML t as (map (map_xml_text f) cs)" + | "map_xml_text f (XML_text txt) = XML_text (f txt)" + (*END: special chars*) + +definition parse_xml_string :: "'a xmlt \ string \ string +\<^sub>\ 'a" + where + "parse_xml_string p str \ case doc_of_string str of + Inl err \ Left err + | Inr (XMLDOC header xml) \ parse_xml p (map_xml_text normalize_special xml)" + + +subsection \For Terminating Parsers\ + +(*TODO: replace the default size of xml *) +primrec size_xml + where "size_xml (XML_text str) = size str" + | "size_xml (XML tag atts xmls) = 1 + size tag + (\xml \ xmls. size_xml xml)" + +abbreviation "size_xml_state \ size_xml \ fst" +abbreviation "size_xmls_state x \ (\xml \ fst x. size_xml xml)" + +lemma size_xml_nth [dest]: "i < length xmls \ size_xml (xmls!i) \ sum_list (map size_xml xmls)" + using elem_le_sum_list[of _ "map Xmlt.size_xml _", unfolded length_map] by auto + +lemma xml_or_cong[fundef_cong]: + assumes "\info. p (fst x, info) = p' (fst x, info)" + and "\info. q (fst x, info) = q' (fst x, info)" + and "x = x'" + shows "(p XMLor q) x = (p' XMLor q') x'" + using assms + by (cases x, auto simp: xml_or_def intro!: Option.bind_cong split:sum.split xml_error.split) + +lemma xml_do_cong[fundef_cong]: + fixes p :: "'a xmlst" + assumes "\tag' atts xmls info. fst x = XML tag' atts xmls \ String.explode tag = tag' \ p (xmls,atts,info) = p' (xmls,atts,info)" + and "x = x'" + shows "xml_do tag p x = xml_do tag p' x'" + using assms by (cases x, auto simp: xml_do_def split: xml.split) + +lemma xml_take_cong[fundef_cong]: + fixes p :: "'a xmlt" and q :: "'a \ 'b xmlst" + assumes "\a as info. fst x = a#as \ p (a, info) = p' (a, info)" + and "\a as ret info info'. x' = (a#as,info) \ q ret (as, info') = q' ret (as, info')" + and "\info. p (XML [] [] [], info) = p' (XML [] [] [], info)" + and "x = x'" + shows "xml_take p q x = xml_take p' q' x'" + using assms by (cases x, auto simp: xml_take_def intro!: Option.bind_cong split: list.split sum.split) + +lemma xml_take_many_cong[fundef_cong]: + fixes p :: "'a xmlt" and q :: "'a list \ 'b xmlst" + assumes p: "\n info. n < length (fst x) \ p (fst x' ! n, info) = p' (fst x' ! n, info)" + and err: "\info. p (XML [] [] [], info) = p' (XML [] [] [], info)" + and q: "\ret n info. q ret (drop n (fst x'), info) = q' ret (drop n (fst x'), info)" + and xx': "x = x'" + shows "xml_take_many_sub ret minOccurs maxOccurs p q x = xml_take_many_sub ret minOccurs maxOccurs p' q' x'" +proof- + obtain as b where x: "x = (as,b)" by (cases x, auto) + show ?thesis + proof (insert p q, fold xx', unfold x, induct as arbitrary: b minOccurs maxOccurs ret) + case Nil + with err show ?case by (cases b, auto intro!: Option.bind_cong) + next + case (Cons a as) + from Cons(2,3)[where n=0] Cons(2,3)[where n="Suc n" for n] + show ?case by (cases b, auto intro!: bind2_cong Cons(1) split: sum.split xml_error.split) + qed qed -(* instantiate this lemma to have the monotonicity lemmas for lists of variable lengths which - are then applicable, e.g., for lists of length 3 it would be - -mono_sum_bot (p1 x) \ mono_sum_bot (p2 x) \ mono_sum_bot (p3 x) -\ mono_sum_bot (\g. Xmlt.options [(k1, \y. p1 y g), (k2, \y. p2 y g), (k3, \y. p3 y g)] x) - -*) -local_setup \fn lthy => - let - val N = 30 (* we require monotonicity lemmas for xml-options for lists up to length N *) - val thy = Proof_Context.theory_of lthy - val options = @{term "Xmlt.options :: (string \ (xml \ (string +\<^sub>\ 'd))) list \ xml \ string +\<^sub>\ 'd"} - val mono_sum_bot = @{term "mono_sum_bot :: (('a \ ('b +\<^sub>\ 'c)) \ string +\<^sub>\ 'd) \ bool"} - val ktyp = @{typ string} - val x = @{term "x :: xml"} - val y = @{term "y :: xml"} - val g = @{term "g :: 'a \ 'b +\<^sub>\ 'c"} - val ptyp = @{typ "xml \ ('a \ ('b +\<^sub>\ 'c)) \ string +\<^sub>\ 'd"} - fun k i = Free ("k" ^ string_of_int i,ktyp) - fun p i = Free ("p" ^ string_of_int i,ptyp) - fun prem i = HOLogic.mk_Trueprop (mono_sum_bot $ (p i $ x)) - fun prems n = 1 upto n |> map prem - fun pair i = HOLogic.mk_prod (k i, lambda y (p i $ y $ g)) - fun pair2 i = HOLogic.mk_prod (k i, p i) - fun list n = 1 upto n |> map pair |> HOLogic.mk_list @{typ "(string \ (xml \ string +\<^sub>\ 'd))"} - fun list2 n = 1 upto n |> map pair2 |> HOLogic.mk_list (HOLogic.mk_prodT (ktyp,ptyp)) - fun concl n = HOLogic.mk_Trueprop (mono_sum_bot $ lambda g (options $ (list n) $ x)) - fun xs n = x :: (1 upto n |> map (fn i => [p i, k i]) |> List.concat) - |> map (fst o dest_Free) - fun tac n pc = - let - val {prems = prems, context = ctxt} = pc - val mono_thm = Thm.instantiate' - (map (SOME o Thm.ctyp_of ctxt) [@{typ 'a},@{typ 'b},@{typ 'c},@{typ 'd}]) - (map (SOME o Thm.cterm_of ctxt) [list2 n,x]) @{thm Xmlt.options_mono_gen} - in - Method.insert_tac ctxt (mono_thm :: prems) 1 THEN force_tac ctxt 1 - end - fun thm n = Goal.prove lthy (xs n) (prems n) (concl n) (tac n) - val thms = map thm (0 upto N) - in Local_Theory.note ((@{binding "options_mono_thms"}, []), thms) lthy |> snd end -\ - -declare Xmlt.options_mono_thms [partial_function_mono] - -fun choice :: "string \ 'a xmlt list \ 'a xmlt" -where - "choice e [] x = error (concat [''error in parsing choice for '', e, ''\'', show x])" | - "choice e (p # ps) x = (try p x catch (\_. choice e ps x))" -hide_const (open) choice - -lemma choice_mono_2 [partial_function_mono]: - assumes p: "mono_sum_bot (p1 x)" - "mono_sum_bot (p2 x)" - shows "mono_sum_bot (\ g. Xmlt.choice e [(\ y. p1 y g), (\ y. p2 y g)] x)" - using p by (auto intro!: partial_function_mono) +lemma xml_take_optional_cong[fundef_cong]: + fixes p :: "'a xmlt" and q :: "'a option \ 'b xmlst" + assumes "\a as info. fst x = a # as \ p (a, info) = p' (a, info)" + and "\a as ret info. fst x = a # as \ q (Some ret) (as, info) = q' (Some ret) (as, info)" + and "\info. q None (fst x', info) = q' None (fst x', info)" + and xx': "x = x'" + shows "xml_take_optional p q x = xml_take_optional p' q' x'" + using assms by (cases x', auto simp: xml_take_optional_def split: list.split sum.split xml_error.split intro!: bind2_cong) -lemma choice_mono_3 [partial_function_mono]: - assumes p: "mono_sum_bot (p1 x)" - "mono_sum_bot (p2 x)" - "mono_sum_bot (p3 x)" - shows "mono_sum_bot (\ g. Xmlt.choice e [(\ y. p1 y g), (\ y. p2 y g), (\ y. p3 y g)] x)" - using p by (auto intro!: partial_function_mono) - -fun change :: "'a xmlt \ ('a \ 'b) \ 'b xmlt" -where - "change p f x = p x \ return \ f" -hide_const (open) change - -lemma change_mono [partial_function_mono]: - assumes p: "\y. mono_sum_bot (p1 y)" - shows "mono_sum_bot (\g. Xmlt.change (\y. p1 y g) f x)" - by (cases x, insert p, auto intro!: partial_function_mono) - -fun int_of_digit :: "char \ string +\<^sub>\ int" -where - "int_of_digit x = - (if x = CHR ''0'' then return 0 - else if x = CHR ''1'' then return 1 - else if x = CHR ''2'' then return 2 - else if x = CHR ''3'' then return 3 - else if x = CHR ''4'' then return 4 - else if x = CHR ''5'' then return 5 - else if x = CHR ''6'' then return 6 - else if x = CHR ''7'' then return 7 - else if x = CHR ''8'' then return 8 - else if x = CHR ''9'' then return 9 - else error (x # '' is not a digit''))" +lemma xml_take_default_cong[fundef_cong]: + fixes p :: "'a xmlt" and q :: "'a \ 'b xmlst" + assumes "\a as info. fst x = a # as \ p (a, info) = p' (a, info)" + and "\a as ret info. fst x = a # as \ q ret (as, info) = q' ret (as, info)" + and "\info. q d (fst x', info) = q' d (fst x', info)" + and xx': "x = x'" + shows "xml_take_default d p q x = xml_take_default d p' q' x'" + using assms by (cases x', auto simp: xml_take_default_def split: list.split sum.split xml_error.split intro!: bind2_cong) -fun int_of_string_aux :: "int \ string \ string +\<^sub>\ int" -where - "int_of_string_aux n [] = return n" | - "int_of_string_aux n (d # s) = (int_of_digit d \ (\m. int_of_string_aux (10 * n + m) s))" - -definition int_of_string :: "string \ string +\<^sub>\ int" -where - "int_of_string s = - (if s = [] then error ''cannot convert empty string into number'' - else if take 1 s = ''-'' then int_of_string_aux 0 (tl s) \ (\ i. return (0 - i)) - else int_of_string_aux 0 s)" - -hide_const int_of_string_aux -fun int :: "tag \ int xmlt" -where - "int tag x = (Xmlt.text tag x \ int_of_string)" -hide_const (open) int +lemma xml_change_cong[fundef_cong]: + assumes "x = x'" + and "p x' = p' x'" + and "\ret y. p x = Right ret \ q ret y = q' ret y" + shows "xml_change p q x = xml_change p' q' x'" + using assms by (cases x', auto simp: xml_change_def split: option.split sum.split intro!: bind2_cong) -fun nat :: "tag \ nat xmlt" -where - "nat tag x = do { - txt \ Xmlt.text tag x; - i \ int_of_string txt; - return (Int.nat i) - }" -hide_const (open) nat -definition rat :: "rat xmlt" -where - "rat = Xmlt.options [ - (''integer'', Xmlt.change (Xmlt.int ''integer'') of_int), - (''rational'', - Xmlt.pair ''rational'' (Xmlt.int ''numerator'') (Xmlt.int ''denominator'') - (\ x y. of_int x / of_int y))]" -hide_const (open) rat +lemma if_cong_applied[fundef_cong]: + "b = c \ + (c \ x z = u w) \ + (\ c \ y z = v w) \ + z = w \ + (if b then x else y) z = (if c then u else v) w" + by auto + +lemma option_case_cong[fundef_cong]: + "option = option' \ + (option' = None \ f1 z = g1 w) \ + (\x2. option' = Some x2 \ f2 x2 z = g2 x2 w) \ + z = w \ + (case option of None \ f1 | Some x2 \ f2 x2) z = (case option' of None \ g1 | Some x2 \ g2 x2) w" + by (cases option, auto) + +lemma sum_case_cong[fundef_cong]: + "s = ss \ + (\x1. ss = Inl x1 \ f1 x1 z = g1 x1 w) \ + (\x2. ss = Inr x2 \ f2 x2 z = g2 x2 w) \ + z = w \ + (case s of Inl x1 \ f1 x1 | Inr x2 \ f2 x2) z = (case ss of Inl x1 \ g1 x1 | Inr x2 \ g2 x2) w" + by (cases s, auto) + +lemma prod_case_cong[fundef_cong]: "p = pp \ + (\x1 x2. pp = (x1, x2) \ f x1 x2 z = g x1 x2 w) \ + (case p of (x1, x2) \ f x1 x2) z = (case pp of (x1, x2) \ g x1 x2) w" + by (auto split: prod.split) + +text \Mononicity rules of combinators for partial-function command.\ + +lemma bind2_mono [partial_function_mono]: + assumes p0: "mono_sum_bot p0" + assumes p1: "\y. mono_sum_bot (p1 y)" + assumes p2: "\y. mono_sum_bot (p2 y)" + shows "mono_sum_bot (\g. bind2 (p0 g) (\y. p1 y g) (\y. p2 y g))" +proof (rule monotoneI) + fix f g :: "'a \ 'b +\<^sub>\ 'c" + assume fg: "fun_ord sum_bot_ord f g" + with p0 have "sum_bot_ord (p0 f) (p0 g)" by (rule monotoneD[of _ _ _ f g]) + then have "sum_bot_ord + (bind2 (p0 f) (\ y. p1 y f) (\ y. p2 y f)) + (bind2 (p0 g) (\ y. p1 y f) (\ y. p2 y f))" + unfolding flat_ord_def bind2_def by auto + also from p1 have "\ y'. sum_bot_ord (p1 y' f) (p1 y' g)" + by (rule monotoneD) (rule fg) + then have "sum_bot_ord + (bind2 (p0 g) (\ y. p1 y f) (\ y. p2 y f)) + (bind2 (p0 g) (\ y. p1 y g) (\ y. p2 y f))" + unfolding flat_ord_def by (cases "p0 g") (auto simp: bind2_def) + also (sum_bot.leq_trans) + from p2 have "\ y'. sum_bot_ord (p2 y' f) (p2 y' g)" + by (rule monotoneD) (rule fg) + then have "sum_bot_ord + (bind2 (p0 g) (\ y. p1 y g) (\ y. p2 y f)) + (bind2 (p0 g) (\ y. p1 y g) (\ y. p2 y g))" + unfolding flat_ord_def by (cases "p0 g") (auto simp: bind2_def) + finally (sum_bot.leq_trans) + show "sum_bot_ord (bind2 (p0 f) (\y. p1 y f) (\y. p2 y f)) + (bind2 (p0 g) (\ya. p1 ya g) (\ya. p2 ya g))" . +qed + +lemma xml_or_mono [partial_function_mono]: + assumes p1: "\y. mono_sum_bot (p1 y)" + assumes p2: "\y. mono_sum_bot (p2 y)" + shows "mono_sum_bot (\g. xml_or (\y. p1 y g) (\y. p2 y g) x)" + using p1 unfolding xml_or_def + by (cases x, auto simp: xml_or_def intro!: partial_function_mono, + intro monotoneI, auto split: xml_error.splits simp: sum_bot.leq_refl dest: monotoneD[OF p2]) + +lemma xml_do_mono [partial_function_mono]: + assumes p1: "\y. mono_sum_bot (p1 y)" + shows "mono_sum_bot (\g. xml_do t (\y. p1 y g) x)" + by (cases x, cases "fst x") (auto simp: xml_do_def intro!: partial_function_mono p1) + +lemma xml_take_mono [partial_function_mono]: + assumes p1: "\y. mono_sum_bot (p1 y)" + assumes p2: "\x z. mono_sum_bot (\ y. p2 z x y)" + shows "mono_sum_bot (\g. xml_take (\y. p1 y g) (\ x y. p2 x y g) x)" +proof (cases x) + case (fields a b c d e) + show ?thesis unfolding xml_take_def fields split + by (cases a, auto intro!: partial_function_mono p2 p1) +qed + +lemma xml_take_default_mono [partial_function_mono]: + assumes p1: "\y. mono_sum_bot (p1 y)" + assumes p2: "\x z. mono_sum_bot (\ y. p2 z x y)" + shows "mono_sum_bot (\g. xml_take_default a (\y. p1 y g) (\ x y. p2 x y g) x)" +proof (cases x) + case (fields a b c d e) + show ?thesis unfolding xml_take_default_def fields split + by (cases a, auto intro!: partial_function_mono p2 p1, intro monotoneI, + auto split: xml_error.splits simp: sum_bot.leq_refl dest: monotoneD[OF p2]) +qed + +lemma xml_take_optional_mono [partial_function_mono]: + assumes p1: "\y. mono_sum_bot (p1 y)" + assumes p2: "\x z. mono_sum_bot (\ y. p2 z x y)" + shows "mono_sum_bot (\g. xml_take_optional (\y. p1 y g) (\ x y. p2 x y g) x)" +proof (cases x) + case (fields a b c d e) + show ?thesis unfolding xml_take_optional_def fields split + by (cases a, auto intro!: partial_function_mono p2 p1, intro monotoneI, + auto split: xml_error.splits simp: sum_bot.leq_refl dest: monotoneD[OF p2]) +qed + +lemma xml_change_mono [partial_function_mono]: + assumes p1: "\y. mono_sum_bot (p1 y)" + assumes p2: "\x z. mono_sum_bot (\ y. p2 z x y)" + shows "mono_sum_bot (\g. xml_change (\y. p1 y g) (\ x y. p2 x y g) x)" + unfolding xml_change_def by (intro partial_function_mono p1, cases x, auto intro: p2) + +lemma xml_take_many_sub_mono [partial_function_mono]: + assumes p1: "\y. mono_sum_bot (p1 y)" + assumes p2: "\x z. mono_sum_bot (\ y. p2 z x y)" + shows "mono_sum_bot (\g. xml_take_many_sub a b c (\y. p1 y g) (\ x y. p2 x y g) x)" +proof - + obtain xs atts allow cands rest where x: "x = (xs, atts, allow, cands, rest)" by (cases x) + show ?thesis unfolding x + proof (induct xs arbitrary: a b c atts allow rest cands) + case Nil + show ?case by (auto intro!: partial_function_mono p1 p2) + next + case (Cons x xs) + show ?case unfolding xml_take_many_sub.simps + by (auto intro!: partial_function_mono p2 p1 Cons, intro monotoneI, + auto split: xml_error.splits simp: sum_bot.leq_refl dest: monotoneD[OF p2]) + qed +qed + +partial_function (sum_bot) xml_foldl :: "('a \ 'b xmlt) \ ('a \ 'b \ 'a) \ 'a \ 'a xmlst" where + [code]: "xml_foldl p f a xs = (case xs of ([],_) \ Right a + | _ \ xml_take (p a) (\ b. xml_foldl p f (f a b)) xs)" end - diff --git a/thys/XML/document/root.tex b/thys/XML/document/root.tex --- a/thys/XML/document/root.tex +++ b/thys/XML/document/root.tex @@ -1,43 +1,43 @@ \documentclass[11pt,a4paper]{article} \usepackage[T1]{fontenc} \usepackage{isabelle,isabellesym} % this should be the last package used \usepackage{pdfsetup} \usepackage[english]{babel} % urls in roman style, theory text in math-similar italics \urlstyle{rm} \isabellestyle{it} \begin{document} \title{Xml\thanks{This research is supported by FWF (Austrian Science Fund) projects J3202 and P22767.}} -\author{Christian Sternagel and Ren\'e Thiemann} +\author{Christian Sternagel, Ren\'e Thiemann and Akihisa Yamada} \maketitle \begin{abstract} This entry provides an ``XML library'' for Isabelle/HOL. This includes parsing and pretty printing of XML trees as well as combinators for transforming XML trees into arbitrary user-defined data. The main contribution of this entry is an interface (fit for code generation) that allows for communication between verified programs formalized in Isabelle/HOL and the outside world via XML. This library was developed as part of the IsaFoR/CeTA project to which we refer for examples of its usage. \end{abstract} \tableofcontents % sane default for proof documents \parindent 0pt\parskip 0.5ex % generated text of all theories \input{session} \end{document} %%% Local Variables: %%% mode: latex %%% TeX-master: t %%% End: